diff --git a/.github/workflows/csv-coverage-pr-artifacts.yml b/.github/workflows/csv-coverage-pr-artifacts.yml
new file mode 100644
index 00000000000..201eea5c073
--- /dev/null
+++ b/.github/workflows/csv-coverage-pr-artifacts.yml
@@ -0,0 +1,97 @@
+name: Check framework coverage changes
+
+on:
+ pull_request:
+ paths:
+ - '.github/workflows/csv-coverage-pr-comment.yml'
+ - '*/ql/src/**/*.ql'
+ - '*/ql/src/**/*.qll'
+ - 'misc/scripts/library-coverage/*.py'
+ # input data files
+ - '*/documentation/library-coverage/cwe-sink.csv'
+ - '*/documentation/library-coverage/frameworks.csv'
+ branches:
+ - main
+ - 'rc/*'
+
+jobs:
+ generate:
+ name: Generate framework coverage artifacts
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJSON(github.event) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Clone self (github/codeql) - MERGE
+ uses: actions/checkout@v2
+ with:
+ path: merge
+ - name: Clone self (github/codeql) - BASE
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 2
+ path: base
+ - run: |
+ git checkout HEAD^1
+ git log -1 --format='%H'
+ working-directory: base
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Download CodeQL CLI
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
+ - name: Unzip CodeQL CLI
+ run: unzip -d codeql-cli codeql-linux64.zip
+ - name: Generate CSV files on merge commit of the PR
+ run: |
+ echo "Running generator on merge"
+ PATH="$PATH:codeql-cli/codeql" python merge/misc/scripts/library-coverage/generate-report.py ci merge merge
+ mkdir out_merge
+ cp framework-coverage-*.csv out_merge/
+ cp framework-coverage-*.rst out_merge/
+ - name: Generate CSV files on base commit of the PR
+ run: |
+ echo "Running generator on base"
+ PATH="$PATH:codeql-cli/codeql" python base/misc/scripts/library-coverage/generate-report.py ci base base
+ mkdir out_base
+ cp framework-coverage-*.csv out_base/
+ cp framework-coverage-*.rst out_base/
+ - name: Generate diff of coverage reports
+ run: |
+ python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
+ - name: Upload CSV package list
+ uses: actions/upload-artifact@v2
+ with:
+ name: csv-framework-coverage-merge
+ path: |
+ out_merge/framework-coverage-*.csv
+ out_merge/framework-coverage-*.rst
+ - name: Upload CSV package list
+ uses: actions/upload-artifact@v2
+ with:
+ name: csv-framework-coverage-base
+ path: |
+ out_base/framework-coverage-*.csv
+ out_base/framework-coverage-*.rst
+ - name: Upload comparison results
+ uses: actions/upload-artifact@v2
+ with:
+ name: comparison
+ path: |
+ comparison.md
+ - name: Save PR number
+ run: |
+ mkdir -p pr
+ echo ${{ github.event.pull_request.number }} > pr/NR
+ - name: Upload PR number
+ uses: actions/upload-artifact@v2
+ with:
+ name: pr
+ path: pr/
diff --git a/.github/workflows/csv-coverage-pr-comment.yml b/.github/workflows/csv-coverage-pr-comment.yml
new file mode 100644
index 00000000000..399fee33e5e
--- /dev/null
+++ b/.github/workflows/csv-coverage-pr-comment.yml
@@ -0,0 +1,34 @@
+name: Comment on PR with framework coverage changes
+
+on:
+ workflow_run:
+ workflows: ["Check framework coverage changes"]
+ types:
+ - completed
+
+jobs:
+ check:
+ name: Check framework coverage differences and comment
+ runs-on: ubuntu-latest
+ if: >
+ ${{ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.conclusion == 'success' }}
+
+ steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJSON(github.event) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Clone self (github/codeql)
+ uses: actions/checkout@v2
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+
+ - name: Check coverage difference file and comment
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RUN_ID: ${{ github.event.workflow_run.id }}
+ run: |
+ python misc/scripts/library-coverage/comment-pr.py "$GITHUB_REPOSITORY" "$RUN_ID"
diff --git a/.github/workflows/csv-coverage-update.yml b/.github/workflows/csv-coverage-update.yml
new file mode 100644
index 00000000000..10834bdd36a
--- /dev/null
+++ b/.github/workflows/csv-coverage-update.yml
@@ -0,0 +1,44 @@
+name: Update framework coverage reports
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ update:
+ name: Update framework coverage report
+ if: github.event.repository.fork == false
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJSON(github.event) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Clone self (github/codeql)
+ uses: actions/checkout@v2
+ with:
+ path: ql
+ fetch-depth: 0
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Download CodeQL CLI
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
+ - name: Unzip CodeQL CLI
+ run: unzip -d codeql-cli codeql-linux64.zip
+
+ - name: Generate coverage files
+ run: |
+ PATH="$PATH:codeql-cli/codeql" python ql/misc/scripts/library-coverage/generate-report.py ci ql ql
+
+ - name: Create pull request with changes
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ python ql/misc/scripts/library-coverage/create-pr.py ql "$GITHUB_REPOSITORY"
diff --git a/CODEOWNERS b/CODEOWNERS
index da670301f30..89529f95924 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -17,3 +17,9 @@
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
+
+# CodeQL tools and associated docs
+/docs/codeql-cli/ @github/codeql-cli-reviewers
+/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
+/docs/ql-language-reference/ @github/codeql-frontend-reviewers
+/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
\ No newline at end of file
diff --git a/config/identical-files.json b/config/identical-files.json
index 582e4c7b6dc..e12be2c91c7 100644
--- a/config/identical-files.json
+++ b/config/identical-files.json
@@ -448,5 +448,17 @@
"SensitiveDataHeuristics Python/JS": [
"javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll"
+ ],
+ "ReDoS Util Python/JS": [
+ "javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll",
+ "python/ql/src/semmle/python/security/performance/ReDoSUtil.qll"
+ ],
+ "ReDoS Exponential Python/JS": [
+ "javascript/ql/src/semmle/javascript/security/performance/ExponentialBackTracking.qll",
+ "python/ql/src/semmle/python/security/performance/ExponentialBackTracking.qll"
+ ],
+ "ReDoS Polynomial Python/JS": [
+ "javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
+ "python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll"
]
}
diff --git a/cpp/change-notes/2021-06-15-path-sensitive-stack-reachability.md b/cpp/change-notes/2021-06-15-path-sensitive-stack-reachability.md
new file mode 100644
index 00000000000..2c57422d860
--- /dev/null
+++ b/cpp/change-notes/2021-06-15-path-sensitive-stack-reachability.md
@@ -0,0 +1,4 @@
+lgtm,codescanning
+* The `StackVariableReachability` library now ignores some paths that contain an infeasible combination
+ of conditionals. These improvements primarily affect the queries `cpp/uninitialized-local` and
+ `cpp/use-after-free`.
\ No newline at end of file
diff --git a/cpp/change-notes/2021-06-21-weak-cryptographic-algorithm.md b/cpp/change-notes/2021-06-21-weak-cryptographic-algorithm.md
new file mode 100644
index 00000000000..8a4bb065eb5
--- /dev/null
+++ b/cpp/change-notes/2021-06-21-weak-cryptographic-algorithm.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The "Use of a broken or risky cryptographic algorithm" (`cpp/weak-cryptographic-algorithm`) query has been further improved to reduce false positives and its `@precision` increased to `high`.
diff --git a/cpp/change-notes/2021-06-24-dataflow-implicit-reads.md b/cpp/change-notes/2021-06-24-dataflow-implicit-reads.md
new file mode 100644
index 00000000000..c96152ed05b
--- /dev/null
+++ b/cpp/change-notes/2021-06-24-dataflow-implicit-reads.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The DataFlow libraries have been augmented with support for `Configuration`-specific in-place read steps at, for example, sinks and custom taint steps. This means that it is now possible to specify sinks that accept flow with non-empty access paths.
diff --git a/cpp/change-notes/2021-06-24-uncontrolled-arithmetic.md b/cpp/change-notes/2021-06-24-uncontrolled-arithmetic.md
new file mode 100644
index 00000000000..a30091f4ea4
--- /dev/null
+++ b/cpp/change-notes/2021-06-24-uncontrolled-arithmetic.md
@@ -0,0 +1,2 @@
+lgtm
+* The 'Uncontrolled data in arithmetic expression' (cpp/uncontrolled-arithmetic) query now recognizes more sources of randomness.
\ No newline at end of file
diff --git a/cpp/change-notes/2021-06-30-wrong-type-format-argument.md b/cpp/change-notes/2021-06-30-wrong-type-format-argument.md
new file mode 100644
index 00000000000..3c0aa3a1260
--- /dev/null
+++ b/cpp/change-notes/2021-06-30-wrong-type-format-argument.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The 'Wrong type of arguments to formatting function' (cpp/wrong-type-format-argument) query is now more accepting of the string and character formatting differences between Microsoft and non-Microsoft platforms. There are now fewer false positive results.
\ No newline at end of file
diff --git a/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql b/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
index ecf739b91be..c8bf3842773 100644
--- a/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
+++ b/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/offset-use-before-range-check
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.2
* @precision medium
* @tags reliability
* security
diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
index 24cd9dc16fd..3ef487fbec2 100644
--- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/descriptor-may-not-be-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/DescriptorNeverClosed.ql b/cpp/ql/src/Critical/DescriptorNeverClosed.ql
index 331d787be62..85e41ad1928 100644
--- a/cpp/ql/src/Critical/DescriptorNeverClosed.ql
+++ b/cpp/ql/src/Critical/DescriptorNeverClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/descriptor-never-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/FileMayNotBeClosed.ql b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
index 395bac61f0b..af38b437778 100644
--- a/cpp/ql/src/Critical/FileMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/file-may-not-be-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/FileNeverClosed.ql b/cpp/ql/src/Critical/FileNeverClosed.ql
index eeeed80af92..b9e71978359 100644
--- a/cpp/ql/src/Critical/FileNeverClosed.ql
+++ b/cpp/ql/src/Critical/FileNeverClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/file-never-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
index 7abfaeb9ebe..6c3435eeba9 100644
--- a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
+++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/global-use-before-init
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.8
* @tags reliability
* security
* external/cwe/cwe-457
diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
index b356c64b3fc..da64be1fdb9 100644
--- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
+++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/inconsistent-nullness-testing
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-476
diff --git a/cpp/ql/src/Critical/InitialisationNotRun.ql b/cpp/ql/src/Critical/InitialisationNotRun.ql
index d4bb90962f7..ba575c55921 100644
--- a/cpp/ql/src/Critical/InitialisationNotRun.ql
+++ b/cpp/ql/src/Critical/InitialisationNotRun.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/initialization-not-run
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-456
diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql
index 98d1d7cba2b..5de36fcc5a9 100644
--- a/cpp/ql/src/Critical/LateNegativeTest.ql
+++ b/cpp/ql/src/Critical/LateNegativeTest.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/late-negative-test
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-823
diff --git a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
index 3726117615e..51467b52be8 100644
--- a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
+++ b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/memory-may-not-be-freed
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags efficiency
* security
* external/cwe/cwe-401
diff --git a/cpp/ql/src/Critical/MemoryNeverFreed.ql b/cpp/ql/src/Critical/MemoryNeverFreed.ql
index 89ca2245d7f..e9593e9d749 100644
--- a/cpp/ql/src/Critical/MemoryNeverFreed.ql
+++ b/cpp/ql/src/Critical/MemoryNeverFreed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/memory-never-freed
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags efficiency
* security
* external/cwe/cwe-401
diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql
index 937510afec6..a4409f2dabf 100644
--- a/cpp/ql/src/Critical/MissingNegativityTest.ql
+++ b/cpp/ql/src/Critical/MissingNegativityTest.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/missing-negativity-test
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-823
diff --git a/cpp/ql/src/Critical/MissingNullTest.ql b/cpp/ql/src/Critical/MissingNullTest.ql
index dcd45f2baf1..b50d06a8dd1 100644
--- a/cpp/ql/src/Critical/MissingNullTest.ql
+++ b/cpp/ql/src/Critical/MissingNullTest.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/missing-null-test
* @problem.severity recommendation
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-476
diff --git a/cpp/ql/src/Critical/NewFreeMismatch.ql b/cpp/ql/src/Critical/NewFreeMismatch.ql
index 09356762e43..19b9b197214 100644
--- a/cpp/ql/src/Critical/NewFreeMismatch.ql
+++ b/cpp/ql/src/Critical/NewFreeMismatch.ql
@@ -3,7 +3,7 @@
* @description An object that was allocated with 'malloc' or 'new' is being freed using a mismatching 'free' or 'delete'.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cpp/new-free-mismatch
* @tags reliability
diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql
index 01cb7b3eaa3..d8a08cc6a69 100644
--- a/cpp/ql/src/Critical/OverflowCalculated.ql
+++ b/cpp/ql/src/Critical/OverflowCalculated.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/overflow-calculated
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @tags reliability
* security
* external/cwe/cwe-131
diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql
index c89ec46cb42..94d46001660 100644
--- a/cpp/ql/src/Critical/OverflowDestination.ql
+++ b/cpp/ql/src/Critical/OverflowDestination.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/overflow-destination
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision low
* @tags reliability
* security
diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql
index d287f43b1c8..7c447c12323 100644
--- a/cpp/ql/src/Critical/OverflowStatic.ql
+++ b/cpp/ql/src/Critical/OverflowStatic.ql
@@ -4,7 +4,7 @@
* may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/static-buffer-overflow
* @tags reliability
diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
index 72ff93e24ab..40082ad5d9c 100644
--- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
+++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/return-stack-allocated-object
* @problem.severity warning
- * @security-severity 2.9
+ * @security-severity 2.1
* @tags reliability
* security
* external/cwe/cwe-562
diff --git a/cpp/ql/src/Critical/SizeCheck.ql b/cpp/ql/src/Critical/SizeCheck.ql
index 7fff35cf717..e7a00ea3621 100644
--- a/cpp/ql/src/Critical/SizeCheck.ql
+++ b/cpp/ql/src/Critical/SizeCheck.ql
@@ -4,7 +4,7 @@
* an instance of the type of the pointer may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 8.1
* @precision medium
* @id cpp/allocation-too-small
* @tags reliability
diff --git a/cpp/ql/src/Critical/SizeCheck2.ql b/cpp/ql/src/Critical/SizeCheck2.ql
index f9a09b66352..eb3aec9a5fe 100644
--- a/cpp/ql/src/Critical/SizeCheck2.ql
+++ b/cpp/ql/src/Critical/SizeCheck2.ql
@@ -4,7 +4,7 @@
* multiple instances of the type of the pointer may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 8.1
* @precision medium
* @id cpp/suspicious-allocation-size
* @tags reliability
diff --git a/cpp/ql/src/Critical/UseAfterFree.ql b/cpp/ql/src/Critical/UseAfterFree.ql
index 1b714267ef1..d770a42b3c2 100644
--- a/cpp/ql/src/Critical/UseAfterFree.ql
+++ b/cpp/ql/src/Critical/UseAfterFree.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/use-after-free
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-416
diff --git a/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql b/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
index ec1a243f245..8672d674d2d 100644
--- a/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
+++ b/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
@@ -7,10 +7,6 @@
import cpp
-class AnonymousCompilation extends Compilation {
- override string toString() { result = "" }
-}
-
string describe(Compilation c) {
if c.getArgument(1) = "--mimic"
then result = "compiler invocation " + concat(int i | i > 1 | c.getArgument(i), " " order by i)
@@ -19,4 +15,4 @@ string describe(Compilation c) {
from Compilation c
where not c.normalTermination()
-select c, "Extraction aborted for " + describe(c), 2
+select "Extraction aborted for " + describe(c)
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
index 1037e4d9063..5a7389205f9 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
@@ -6,7 +6,7 @@
* to a larger type.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision very-high
* @id cpp/bad-addition-overflow-check
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
index 941fecc453d..03ad085b6d3 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
@@ -4,7 +4,7 @@
* be a sign that the result can overflow the type converted from.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/integer-multiplication-cast-to-long
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
index 6da994e6729..7911049599a 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
@@ -5,7 +5,7 @@
* unsigned integer values.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/signed-overflow-check
* @tags correctness
diff --git a/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql b/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
index 19e50a3f368..9032919da44 100644
--- a/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
+++ b/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
@@ -6,7 +6,7 @@
* use the width of the base type, leading to misaligned reads.
* @kind path-problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cpp/upcast-array-pointer-arithmetic
* @tags correctness
diff --git a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
index f480501f7ba..f00dfa2213b 100644
--- a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
+++ b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
@@ -6,7 +6,7 @@
* from an untrusted source, this can be used for exploits.
* @kind problem
* @problem.severity recommendation
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/non-constant-format
* @tags maintainability
diff --git a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
index 78427655c22..7da8db7f226 100644
--- a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
@@ -3,7 +3,7 @@
* @description Using the return value from snprintf without proper checks can cause overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/overflowing-snprintf
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
index 1147c6c66a1..cc3510ee5eb 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
@@ -4,7 +4,7 @@
* a source of security issues.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision high
* @id cpp/wrong-number-format-arguments
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
index d1624e484fe..cb5a5209ffe 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
@@ -4,7 +4,7 @@
* behavior.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cpp/wrong-type-format-argument
* @tags reliability
@@ -19,28 +19,32 @@ import cpp
* Holds if the argument corresponding to the `pos` conversion specifier
* of `ffc` is expected to have type `expected`.
*/
-pragma[noopt]
private predicate formattingFunctionCallExpectedType(
FormattingFunctionCall ffc, int pos, Type expected
) {
- exists(FormattingFunction f, int i, FormatLiteral fl |
- ffc instanceof FormattingFunctionCall and
- ffc.getTarget() = f and
- f.getFormatParameterIndex() = i and
- ffc.getArgument(i) = fl and
- fl.getConversionType(pos) = expected
- )
+ ffc.getFormat().(FormatLiteral).getConversionType(pos) = expected
}
/**
* Holds if the argument corresponding to the `pos` conversion specifier
- * of `ffc` is expected to have type `expected` and the corresponding
- * argument `arg` has type `actual`.
+ * of `ffc` could alternatively have type `expected`, for example on a different
+ * platform.
+ */
+private predicate formattingFunctionCallAlternateType(
+ FormattingFunctionCall ffc, int pos, Type expected
+) {
+ ffc.getFormat().(FormatLiteral).getConversionTypeAlternate(pos) = expected
+}
+
+/**
+ * Holds if the argument corresponding to the `pos` conversion specifier
+ * of `ffc` is `arg` and has type `actual`.
*/
pragma[noopt]
-predicate formatArgType(FormattingFunctionCall ffc, int pos, Type expected, Expr arg, Type actual) {
+predicate formattingFunctionCallActualType(
+ FormattingFunctionCall ffc, int pos, Expr arg, Type actual
+) {
exists(Expr argConverted |
- formattingFunctionCallExpectedType(ffc, pos, expected) and
ffc.getConversionArgument(pos) = arg and
argConverted = arg.getFullyConverted() and
actual = argConverted.getType()
@@ -72,7 +76,8 @@ class ExpectedType extends Type {
ExpectedType() {
exists(Type t |
(
- formatArgType(_, _, t, _, _) or
+ formattingFunctionCallExpectedType(_, _, t) or
+ formattingFunctionCallAlternateType(_, _, t) or
formatOtherArgType(_, _, t, _, _)
) and
this = t.getUnspecifiedType()
@@ -91,7 +96,11 @@ class ExpectedType extends Type {
*/
predicate trivialConversion(ExpectedType expected, Type actual) {
exists(Type exp, Type act |
- formatArgType(_, _, exp, _, act) and
+ (
+ formattingFunctionCallExpectedType(_, _, exp) or
+ formattingFunctionCallAlternateType(_, _, exp)
+ ) and
+ formattingFunctionCallActualType(_, _, _, act) and
expected = exp.getUnspecifiedType() and
actual = act.getUnspecifiedType()
) and
@@ -146,9 +155,13 @@ int sizeof_IntType() { exists(IntType it | result = it.getSize()) }
from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual
where
(
- formatArgType(ffc, n, expected, arg, actual) and
+ formattingFunctionCallExpectedType(ffc, n, expected) and
+ formattingFunctionCallActualType(ffc, n, arg, actual) and
not exists(Type anyExpected |
- formatArgType(ffc, n, anyExpected, arg, actual) and
+ (
+ formattingFunctionCallExpectedType(ffc, n, anyExpected) or
+ formattingFunctionCallAlternateType(ffc, n, anyExpected)
+ ) and
trivialConversion(anyExpected.getUnspecifiedType(), actual.getUnspecifiedType())
)
or
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
index 1b20aa1b224..30664869adc 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/incorrect-not-operator-usage
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-480
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
index 1af4ba839b5..61d7a266d86 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
@@ -3,7 +3,7 @@
* @description Using alloca in a loop can lead to a stack overflow
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cpp/alloca-in-loop
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
index c72086060fd..7f1541f7ea8 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/improper-null-termination
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security
* external/cwe/cwe-170
* external/cwe/cwe-665
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql b/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
index 3035d3ba2ea..e11d114d1fb 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
@@ -4,7 +4,7 @@
* on undefined behavior and may lead to memory corruption.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 2.1
* @precision high
* @id cpp/pointer-overflow-check
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
index 4a9fc949f89..8e7bc5bfcf4 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
@@ -4,7 +4,7 @@
* as the third argument may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/bad-strncpy-size
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
index 28742629b37..644c48622a2 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
@@ -3,7 +3,7 @@
* @description Calling 'strncat' with an incorrect size argument may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/unsafe-strncat
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
index 9198cd0497e..a80af562bda 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
@@ -5,7 +5,7 @@
* the machine pointer size.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-sizeof
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
index 94e230e8838..5861167659f 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/uninitialized-local
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @tags security
* external/cwe/cwe-665
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql b/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
index 2eb8d0b4060..d0b0f7f1e71 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
@@ -4,7 +4,7 @@
* may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cpp/unsafe-strcat
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
index 2702cbdcea7..9ddf445f4bf 100644
--- a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
+++ b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/self-assignment-check
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.0
* @tags reliability
* security
* external/cwe/cwe-826
diff --git a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
index 746a2761e49..04325e8497e 100644
--- a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
+++ b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
@@ -6,7 +6,7 @@
* @kind path-problem
* @id cpp/unsafe-use-of-this
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision very-high
* @tags correctness
* language-features
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
index 3196143c5d1..bc53015c905 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
@@ -7,7 +7,7 @@
* undefined data.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision very-high
* @id cpp/too-few-arguments
* @tags correctness
diff --git a/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql b/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql
index fb25a93963d..bf52b2bb615 100644
--- a/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql
+++ b/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql
@@ -9,7 +9,6 @@
* @tags reliability
* external/cwe/cwe-573
* external/cwe/cwe-252
- * @opaque-id SM02344
* @microsoft.severity Important
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
index 77c4f149cac..33c31972295 100644
--- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/memset-may-be-deleted
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.8
* @precision high
* @tags security
* external/cwe/cwe-14
diff --git a/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql b/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
index 0396d5c7bb0..47a0bf14b7f 100644
--- a/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
+++ b/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql b/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
index 196fe57f74b..b85a5b26a7f 100644
--- a/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
+++ b/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
index c96b6f6dc5b..5e22506d03a 100644
--- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
+++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
@@ -4,7 +4,7 @@
* attacker to access unexpected resources.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/path-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
index d3020406f15..5f516eec83b 100644
--- a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
@@ -5,7 +5,7 @@
* to command injection.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @id cpp/command-line-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
index 0b56e972320..bb38609927e 100644
--- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
+++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision high
* @id cpp/cgi-xss
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
index 1e4536f0942..a3f935170d7 100644
--- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
@@ -5,7 +5,7 @@
* to SQL Injection.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cpp/sql-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
index 3aba72ed741..e75f62b0eb7 100644
--- a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
+++ b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
@@ -5,7 +5,7 @@
* commands.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.0
+ * @security-severity 8.2
* @precision medium
* @id cpp/uncontrolled-process-operation
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
index c61498ac2e0..1c903081baf 100644
--- a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
+++ b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/overflow-buffer
* @problem.severity recommendation
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags security
* external/cwe/cwe-119
* external/cwe/cwe-121
diff --git a/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
index 01d8d8db4e2..247606c683d 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
@@ -5,7 +5,7 @@
* overflow.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision high
* @id cpp/badly-bounded-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
index 6832561e10c..ac4144d1c6f 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
@@ -4,7 +4,7 @@
* of data written may overflow.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/overrunning-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql b/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
index 73ef5e62fb2..27adab9b06c 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
@@ -5,7 +5,7 @@
* take extreme values.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/overrunning-write-with-float
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
index 656b52b03bf..b9922da9c75 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
@@ -4,7 +4,7 @@
* of data written may overflow.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/unbounded-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
index 3dacc443a74..842798102bd 100644
--- a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
+++ b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
@@ -5,7 +5,7 @@
* a specific value to terminate the argument list.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/unterminated-variadic-call
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
index 59498017b1f..0621def4d98 100644
--- a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
+++ b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/unclear-array-index-validation
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @tags security
* external/cwe/cwe-129
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
index b31213b09f3..1780c2a0199 100644
--- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
+++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
@@ -5,7 +5,7 @@
* terminator can cause a buffer overrun.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cpp/no-space-for-terminator
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
index 0593679c3f5..f24510bba05 100644
--- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
+++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
index 67853b9e361..d2f5243d4a4 100644
--- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
+++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string-through-global
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
index ad4d0389f0c..e00bd87c86a 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
@@ -2,9 +2,9 @@
* @name User-controlled data in arithmetic expression
* @description Arithmetic operations on user-controlled data that is
* not validated can cause overflows.
- * @kind problem
+ * @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision low
* @id cpp/tainted-arithmetic
* @tags security
@@ -16,22 +16,39 @@ import cpp
import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking
+import TaintedWithPath
+import Bounded
-from Expr origin, Operation op, Expr e, string effect
+bindingset[op]
+predicate missingGuard(Operation op, Expr e, string effect) {
+ missingGuardAgainstUnderflow(op, e) and effect = "underflow"
+ or
+ missingGuardAgainstOverflow(op, e) and effect = "overflow"
+ or
+ not e instanceof VariableAccess and effect = "overflow"
+}
+
+class Configuration extends TaintTrackingConfiguration {
+ override predicate isSink(Element e) {
+ exists(Operation op |
+ missingGuard(op, e, _) and
+ op.getAnOperand() = e
+ |
+ op instanceof UnaryArithmeticOperation or
+ op instanceof BinaryArithmeticOperation
+ )
+ }
+
+ override predicate isBarrier(Expr e) {
+ super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
+ }
+}
+
+from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op
where
- isUserInput(origin, _) and
- tainted(origin, e) and
+ taintedWithPath(origin, e, sourceNode, sinkNode) and
op.getAnOperand() = e and
- (
- missingGuardAgainstUnderflow(op, e) and effect = "underflow"
- or
- missingGuardAgainstOverflow(op, e) and effect = "overflow"
- or
- not e instanceof VariableAccess and effect = "overflow"
- ) and
- (
- op instanceof UnaryArithmeticOperation or
- op instanceof BinaryArithmeticOperation
- )
-select e, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
- origin, "User-provided value"
+ missingGuard(op, e, effect)
+select e, sourceNode, sinkNode,
+ "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
+ "User-provided value"
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
index 359ac7a0d1a..0d13447f7fc 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
@@ -4,7 +4,7 @@
* validated can cause overflows.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id cpp/uncontrolled-arithmetic
* @tags security
@@ -15,108 +15,63 @@
import cpp
import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
-import semmle.code.cpp.security.TaintTracking
-import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
-import TaintedWithPath
+import semmle.code.cpp.security.FlowSources
+import semmle.code.cpp.ir.dataflow.TaintTracking
+import DataFlow::PathGraph
+import Bounded
-predicate isUnboundedRandCall(FunctionCall fc) {
- exists(Function func | func = fc.getTarget() |
- func.hasGlobalOrStdOrBslName("rand") and
- not bounded(fc) and
- func.getNumberOfParameters() = 0
- )
+/**
+ * A function that outputs random data such as `std::rand`.
+ */
+abstract class RandomFunction extends Function {
+ /**
+ * Gets the `FunctionOutput` that describes how this function returns the random data.
+ */
+ FunctionOutput getFunctionOutput() { result.isReturnValue() }
}
/**
- * An operand `e` of a division expression (i.e., `e` is an operand of either a `DivExpr` or
- * a `AssignDivExpr`) is bounded when `e` is the left-hand side of the division.
+ * The standard function `std::rand`.
*/
-pragma[inline]
-predicate boundedDiv(Expr e, Expr left) { e = left }
-
-/**
- * An operand `e` of a remainder expression `rem` (i.e., `rem` is either a `RemExpr` or
- * an `AssignRemExpr`) with left-hand side `left` and right-ahnd side `right` is bounded
- * when `e` is `left` and `right` is upper bounded by some number that is less than the maximum integer
- * allowed by the result type of `rem`.
- */
-pragma[inline]
-predicate boundedRem(Expr e, Expr rem, Expr left, Expr right) {
- e = left and
- upperBound(right.getFullyConverted()) < exprMaxVal(rem.getFullyConverted())
-}
-
-/**
- * An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
- * or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
- * bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
- */
-pragma[inline]
-predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
- operand1 != operand2 and
- e = operand1 and
- upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
-}
-
-/**
- * Holds if `fc` is a part of the left operand of a binary operation that greatly reduces the range
- * of possible values.
- */
-predicate bounded(Expr e) {
- // For `%` and `&` we require that `e` is bounded by a value that is strictly smaller than the
- // maximum possible value of the result type of the operation.
- // For example, the function call `rand()` is considered bounded in the following program:
- // ```
- // int i = rand() % (UINT8_MAX + 1);
- // ```
- // but not in:
- // ```
- // unsigned char uc = rand() % (UINT8_MAX + 1);
- // ```
- exists(RemExpr rem | boundedRem(e, rem, rem.getLeftOperand(), rem.getRightOperand()))
- or
- exists(AssignRemExpr rem | boundedRem(e, rem, rem.getLValue(), rem.getRValue()))
- or
- exists(BitwiseAndExpr andExpr |
- boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
- )
- or
- exists(AssignAndExpr andExpr |
- boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
- )
- or
- // Optimitically assume that a division always yields a much smaller value.
- boundedDiv(e, any(DivExpr div).getLeftOperand())
- or
- boundedDiv(e, any(AssignDivExpr div).getLValue())
- or
- boundedDiv(e, any(RShiftExpr shift).getLeftOperand())
- or
- boundedDiv(e, any(AssignRShiftExpr div).getLValue())
-}
-
-predicate isUnboundedRandCallOrParent(Expr e) {
- isUnboundedRandCall(e)
- or
- isUnboundedRandCallOrParent(e.getAChild())
-}
-
-predicate isUnboundedRandValue(Expr e) {
- isUnboundedRandCall(e)
- or
- exists(MacroInvocation mi |
- e = mi.getExpr() and
- isUnboundedRandCallOrParent(e)
- )
-}
-
-class SecurityOptionsArith extends SecurityOptions {
- override predicate isUserInput(Expr expr, string cause) {
- isUnboundedRandValue(expr) and
- cause = "rand"
+private class StdRand extends RandomFunction {
+ StdRand() {
+ this.hasGlobalOrStdOrBslName("rand") and
+ this.getNumberOfParameters() = 0
}
}
+/**
+ * The Unix function `rand_r`.
+ */
+private class RandR extends RandomFunction {
+ RandR() {
+ this.hasGlobalName("rand_r") and
+ this.getNumberOfParameters() = 1
+ }
+}
+
+/**
+ * The Unix function `random`.
+ */
+private class Random extends RandomFunction {
+ Random() {
+ this.hasGlobalName("random") and
+ this.getNumberOfParameters() = 1
+ }
+}
+
+/**
+ * The Windows `rand_s` function.
+ */
+private class RandS extends RandomFunction {
+ RandS() {
+ this.hasGlobalName("rand_s") and
+ this.getNumberOfParameters() = 1
+ }
+
+ override FunctionOutput getFunctionOutput() { result.isParameterDeref(0) }
+}
+
predicate missingGuard(VariableAccess va, string effect) {
exists(Operation op | op.getAnOperand() = va |
missingGuardAgainstUnderflow(op, va) and effect = "underflow"
@@ -125,16 +80,47 @@ predicate missingGuard(VariableAccess va, string effect) {
)
}
-class Configuration extends TaintTrackingConfiguration {
- override predicate isSink(Element e) { missingGuard(e, _) }
+class UncontrolledArithConfiguration extends TaintTracking::Configuration {
+ UncontrolledArithConfiguration() { this = "UncontrolledArithConfiguration" }
- override predicate isBarrier(Expr e) { super.isBarrier(e) or bounded(e) }
+ override predicate isSource(DataFlow::Node source) {
+ exists(RandomFunction rand, Call call | call.getTarget() = rand |
+ rand.getFunctionOutput().isReturnValue() and
+ source.asExpr() = call
+ or
+ exists(int n |
+ source.asDefiningArgument() = call.getArgument(n) and
+ rand.getFunctionOutput().isParameterDeref(n)
+ )
+ )
+ }
+
+ override predicate isSink(DataFlow::Node sink) { missingGuard(sink.asExpr(), _) }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ bounded(node.asExpr())
+ or
+ // If this expression is part of bitwise 'and' or 'or' operation it's likely that the value is
+ // only used as a bit pattern.
+ node.asExpr() =
+ any(Operation op |
+ op instanceof BitwiseOrExpr or
+ op instanceof BitwiseAndExpr or
+ op instanceof ComplementExpr
+ ).getAnOperand*()
+ }
}
-from Expr origin, VariableAccess va, string effect, PathNode sourceNode, PathNode sinkNode
+/** Gets the expression that corresponds to `node`, if any. */
+Expr getExpr(DataFlow::Node node) { result = [node.asExpr(), node.asDefiningArgument()] }
+
+from
+ UncontrolledArithConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
+ VariableAccess va, string effect
where
- taintedWithPath(origin, va, sourceNode, sinkNode) and
+ config.hasFlowPath(source, sink) and
+ sink.getNode().asExpr() = va and
missingGuard(va, effect)
-select va, sourceNode, sinkNode,
- "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
- "Uncontrolled value"
+select sink.getNode(), source, sink,
+ "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
+ getExpr(source.getNode()), "Uncontrolled value"
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
index 9addbab5c1c..35668953acc 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/arithmetic-with-extreme-values
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision low
* @tags security
* reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-190/Bounded.qll b/cpp/ql/src/Security/CWE/CWE-190/Bounded.qll
new file mode 100644
index 00000000000..b6b0d608d2a
--- /dev/null
+++ b/cpp/ql/src/Security/CWE/CWE-190/Bounded.qll
@@ -0,0 +1,55 @@
+/**
+ * This file provides the `bounded` predicate that is used in both `cpp/uncontrolled-arithmetic`
+ * and `cpp/tainted-arithmetic`.
+ */
+
+private import cpp
+private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
+private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
+
+/**
+ * An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
+ * or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
+ * bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
+ */
+pragma[inline]
+private predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
+ operand1 != operand2 and
+ e = operand1 and
+ upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
+}
+
+/**
+ * Holds if `e` is an arithmetic expression that cannot overflow, or if `e` is an operand of an
+ * operation that may greatly reduce the range of possible values.
+ */
+predicate bounded(Expr e) {
+ (
+ e instanceof UnaryArithmeticOperation or
+ e instanceof BinaryArithmeticOperation or
+ e instanceof AssignArithmeticOperation
+ ) and
+ not convertedExprMightOverflow(e)
+ or
+ // Optimitically assume that a remainder expression always yields a much smaller value.
+ e = any(RemExpr rem).getLeftOperand()
+ or
+ e = any(AssignRemExpr rem).getLValue()
+ or
+ exists(BitwiseAndExpr andExpr |
+ boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
+ )
+ or
+ exists(AssignAndExpr andExpr |
+ boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
+ )
+ or
+ // Optimitically assume that a division always yields a much smaller value.
+ e = any(DivExpr div).getLeftOperand()
+ or
+ e = any(AssignDivExpr div).getLValue()
+ or
+ e = any(RShiftExpr shift).getLeftOperand()
+ or
+ e = any(AssignRShiftExpr div).getLValue()
+}
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index 1ec3c6554fe..6636d100746 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -5,7 +5,7 @@
* @id cpp/comparison-with-wider-type
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @tags reliability
* security
diff --git a/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql b/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
index 7e4880ffca6..bc0dff58244 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/integer-overflow-tainted
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision low
* @tags security
* external/cwe/cwe-190
diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
index 765a2519a38..585875798cc 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
@@ -4,7 +4,7 @@
* user can result in integer overflow.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision medium
* @id cpp/uncontrolled-allocation-size
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
index ddd7bf3430f..5be71472c92 100644
--- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
+++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/unsigned-difference-expression-compared-zero
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @tags security
* correctness
diff --git a/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql b/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
index bde1e265690..67ba5b0c45b 100644
--- a/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
+++ b/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/hresult-boolean-conversion
* @problem.severity error
- * @security-severity 4.2
+ * @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-253
diff --git a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
index 7cdd5c34b8b..814c6aff21b 100644
--- a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
+++ b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
@@ -5,7 +5,7 @@
* vulnerable to spoofing attacks.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.8
+ * @security-severity 8.1
* @precision medium
* @id cpp/user-controlled-bypass
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
index 6785700d077..696c5764fcd 100644
--- a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
@@ -4,7 +4,7 @@
* to an attacker.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-buffer
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
index fcf2a00435e..aa90ff9567c 100644
--- a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
@@ -4,7 +4,7 @@
* to an attacker.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-file
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
index ccb67f54d3a..bb9135a92ff 100644
--- a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
+++ b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
@@ -4,7 +4,7 @@
* database can expose it to an attacker.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-database
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
index 848adfd7adc..e6c7b186ce2 100644
--- a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
+++ b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
@@ -4,8 +4,8 @@
* an attacker to compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
- * @precision medium
+ * @security-severity 7.5
+ * @precision high
* @id cpp/weak-cryptographic-algorithm
* @tags security
* external/cwe/cwe-327
@@ -70,9 +70,12 @@ EnumConstant getAdditionalEvidenceEnumConst() { isEncryptionAdditionalEvidence(r
predicate getInsecureEncryptionEvidence(FunctionCall fc, Element blame, string description) {
// find use of an insecure algorithm name
(
- fc.getTarget() = getAnInsecureEncryptionFunction() and
- blame = fc and
- description = "call to " + fc.getTarget().getName()
+ exists(FunctionCall fc2 |
+ fc.getAChild*() = fc2 and
+ fc2.getTarget() = getAnInsecureEncryptionFunction() and
+ blame = fc2 and
+ description = "call to " + fc.getTarget().getName()
+ )
or
exists(MacroInvocation mi |
(
@@ -93,7 +96,10 @@ predicate getInsecureEncryptionEvidence(FunctionCall fc, Element blame, string d
) and
// find additional evidence that this function is related to encryption.
(
- fc.getTarget() = getAnAdditionalEvidenceFunction()
+ exists(FunctionCall fc2 |
+ fc.getAChild*() = fc2 and
+ fc2.getTarget() = getAnAdditionalEvidenceFunction()
+ )
or
exists(MacroInvocation mi |
(
@@ -107,6 +113,27 @@ predicate getInsecureEncryptionEvidence(FunctionCall fc, Element blame, string d
ec = fc.getAnArgument() and
ec.getTarget() = getAdditionalEvidenceEnumConst()
)
+ ) and
+ // exclude calls from templates as this is rarely the right place to flag an
+ // issue
+ not fc.isFromTemplateInstantiation(_) and
+ (
+ // the function should have an input that looks like a non-constant buffer
+ exists(Expr e |
+ fc.getAnArgument() = e and
+ (
+ e.getUnspecifiedType() instanceof PointerType or
+ e.getUnspecifiedType() instanceof ReferenceType or
+ e.getUnspecifiedType() instanceof ArrayType
+ ) and
+ not e.getType().isDeeplyConstBelow() and
+ not e.isConstant()
+ )
+ or
+ // or be a non-const member function of an object
+ fc.getTarget() instanceof MemberFunction and
+ not fc.getTarget() instanceof ConstMemberFunction and
+ not fc.getTarget().isStatic()
)
}
diff --git a/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql b/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
index 5ee196994ac..38067ae200c 100644
--- a/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
+++ b/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
@@ -4,7 +4,7 @@
* attackers to retrieve portions of memory.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision very-high
* @id cpp/openssl-heartbleed
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
index 7d19e323f2b..93808e3a911 100644
--- a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
+++ b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
@@ -5,7 +5,7 @@
* the two operations.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.7
* @precision medium
* @id cpp/toctou-race-condition
* @tags security
@@ -16,10 +16,13 @@ import cpp
import semmle.code.cpp.controlflow.Guards
/**
- * An operation on a filename.
+ * An operation on a filename that is likely to modify the corresponding file
+ * and may return an indication of success.
*
- * Note: we're not interested in operations on file descriptors, as they
- * are better behaved.
+ * Note: we're not interested in operations where the file is specified by a
+ * descriptor, rather than a filename, as they are better behaved. We are
+ * interested in functions that take a filename and return a file descriptor,
+ * however.
*/
FunctionCall filenameOperation(Expr path) {
exists(string name | name = result.getTarget().getName() |
@@ -48,7 +51,8 @@ FunctionCall filenameOperation(Expr path) {
}
/**
- * A use of `access` (or similar) on a filename.
+ * An operation on a filename that returns information in the return value but
+ * does not modify the corresponding file. For example, `access`.
*/
FunctionCall accessCheck(Expr path) {
exists(string name | name = result.getTarget().getName() |
@@ -62,7 +66,9 @@ FunctionCall accessCheck(Expr path) {
}
/**
- * A use of `stat` (or similar) on a filename.
+ * An operation on a filename that returns information via a pointer argument
+ * and any return value, but does not modify the corresponding file. For
+ * example, `stat`.
*/
FunctionCall stat(Expr path, Expr buf) {
exists(string name | name = result.getTarget().getName() |
@@ -77,7 +83,7 @@ FunctionCall stat(Expr path, Expr buf) {
}
/**
- * Holds if `use` points to `source`, either by being the same or by
+ * Holds if `use` refers to `source`, either by being the same or by
* one step of variable indirection.
*/
predicate referenceTo(Expr source, Expr use) {
@@ -88,36 +94,38 @@ predicate referenceTo(Expr source, Expr use) {
)
}
-from FunctionCall fc, Expr check, Expr checkUse, Expr opUse
+from Expr check, Expr checkPath, FunctionCall use, Expr usePath
where
- // checkUse looks like a check on a filename
+ // `check` looks like a check on a filename
(
// either:
// an access check
- check = accessCheck(checkUse)
+ check = accessCheck(checkPath)
or
// a stat
- check = stat(checkUse, _)
+ check = stat(checkPath, _)
or
// another filename operation (null pointers can indicate errors)
- check = filenameOperation(checkUse)
+ check = filenameOperation(checkPath)
or
// access to a member variable on the stat buf
// (morally, this should be a use-use pair, but it seems unlikely
// that this variable will get reused in practice)
- exists(Variable buf | exists(stat(checkUse, buf.getAnAccess())) |
+ exists(Variable buf | exists(stat(checkPath, buf.getAnAccess())) |
check.(VariableAccess).getQualifier() = buf.getAnAccess()
)
) and
- // checkUse and opUse refer to the same SSA variable
- exists(SsaDefinition def, StackVariable v | def.getAUse(v) = checkUse and def.getAUse(v) = opUse) and
- // opUse looks like an operation on a filename
- fc = filenameOperation(opUse) and
- // the return value of check is used (possibly with one step of
- // variable indirection) in a guard which controls fc
+ // `checkPath` and `usePath` refer to the same SSA variable
+ exists(SsaDefinition def, StackVariable v |
+ def.getAUse(v) = checkPath and def.getAUse(v) = usePath
+ ) and
+ // `op` looks like an operation on a filename
+ use = filenameOperation(usePath) and
+ // the return value of `check` is used (possibly with one step of
+ // variable indirection) in a guard which controls `use`
exists(GuardCondition guard | referenceTo(check, guard.getAChild*()) |
- guard.controls(fc.(ControlFlowNode).getBasicBlock(), _)
+ guard.controls(use.(ControlFlowNode).getBasicBlock(), _)
)
-select fc,
+select use,
"The $@ being operated upon was previously $@, but the underlying file may have been changed since then.",
- opUse, "filename", check, "checked"
+ usePath, "filename", check, "checked"
diff --git a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
index 73e0d8794ad..7c540e9d313 100644
--- a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
+++ b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
@@ -4,7 +4,7 @@
* @id cpp/unsafe-create-process-call
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @msrc.severity important
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
index 3d6c54e33ae..9a08bbd64a6 100644
--- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
+++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
@@ -5,8 +5,7 @@
* state, and reading the variable may result in undefined behavior.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
- * @opaque-id SM02313
+ * @security-severity 7.8
* @id cpp/conditionally-uninitialized-variable
* @tags security
* external/cwe/cwe-457
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
index a582813ed5f..ce99ce1ebce 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
@@ -4,7 +4,7 @@
* can cause buffer overflow conditions.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-pointer-scaling
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
index c1bfb9c4ee9..5b7e3379929 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/incorrect-pointer-scaling-char
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision low
* @tags security
* external/cwe/cwe-468
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
index aa267a25f4e..460c98bf1e3 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
@@ -4,7 +4,7 @@
* can cause buffer overflow conditions.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-pointer-scaling-void
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
index 7532f7e9fcf..4ac00fc42c6 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
@@ -5,7 +5,7 @@
* implicitly scaled.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @id cpp/suspicious-add-sizeof
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
index ead50c9620e..bbe3b0805e1 100644
--- a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
+++ b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
@@ -5,7 +5,7 @@
* attack plan.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision medium
* @id cpp/system-data-exposure
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql b/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
index 321684dc93c..65551a1f138 100644
--- a/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
+++ b/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/incorrect-string-type-conversion
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @tags security
* external/cwe/cwe-704
diff --git a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
index 67dce658ed8..1fd55a02d01 100644
--- a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
+++ b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
@@ -3,7 +3,7 @@
* @description Creating a file that is world-writable can allow an attacker to write to the file.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @id cpp/world-writable-file-creation
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
index 72399cec376..bf673826347 100644
--- a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
+++ b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
@@ -7,7 +7,7 @@
* @id cpp/unsafe-dacl-security-descriptor
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @tags security
* external/cwe/cwe-732
diff --git a/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql b/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
index 2a0d765f239..cd5d8771807 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/lock-order-cycle
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @tags security
* external/cwe/cwe-764
* external/cwe/cwe-833
diff --git a/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql b/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
index c32e747f3e4..051ad2eeeea 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/twice-locked
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision low
* @tags security
* external/cwe/cwe-764
diff --git a/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql b/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
index 8f3d9e92149..dd224352b12 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/unreleased-lock
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision low
* @tags security
* external/cwe/cwe-764
diff --git a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
index 08a5ceb49db..64505ee8283 100644
--- a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
+++ b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
@@ -5,7 +5,7 @@
* attack.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/tainted-permissions-check
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql b/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
index cd85179d14d..3db5e15874b 100644
--- a/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
+++ b/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/infinite-loop-with-unsatisfiable-exit-condition
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-835
*/
diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql
index 2d816b349e8..3b2aa2ac4c9 100644
--- a/cpp/ql/src/Summary/LinesOfCode.ql
+++ b/cpp/ql/src/Summary/LinesOfCode.ql
@@ -4,7 +4,6 @@
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
- * lines-of-code
*/
import cpp
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.c b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.c
new file mode 100644
index 00000000000..3e2467fbb66
--- /dev/null
+++ b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.c
@@ -0,0 +1,12 @@
+intA = ++intA + 1; // BAD: undefined behavior when changing variable `intA`
+...
+intA++;
+intA = intA + 1; // GOOD: correct design
+...
+char * buff;
+...
+if(funcAdd(buff)+fucDel(buff)>0) return 1; // BAD: undefined behavior when calling functions to change the `buff` variable
+...
+intA = funcAdd(buff);
+intB = funcDel(buff);
+if(intA+intB>0) return 1; // GOOD: correct design
\ No newline at end of file
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.qhelp
new file mode 100644
index 00000000000..aa32e2517a3
--- /dev/null
+++ b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.qhelp
@@ -0,0 +1,28 @@
+
+
+
+In some situations, the code constructs used may be executed in the wrong order in which the developer designed them. For example, if you call multiple functions as part of a single expression, and the functions have the ability to modify a shared resource, then the sequence in which the resource is changed can be unpredictable. These code snippets look suspicious and require the developer's attention.
+
+
+
+
+
+We recommend that you use more guaranteed, in terms of sequence of execution, coding techniques.
+
+
+
+The following example demonstrates sections of code with insufficient execution sequence definition.
+
+
+
+
+
+
+ CWE Common Weakness Enumeration:
+ EXP10-C. Do not depend on the order of evaluation of subexpressions or the order in which side effects take place .
+
+
+
+
\ No newline at end of file
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.ql b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.ql
new file mode 100644
index 00000000000..a1dce27f81c
--- /dev/null
+++ b/cpp/ql/src/experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.ql
@@ -0,0 +1,166 @@
+/**
+ * @name Errors Of Undefined Program Behavior
+ * @description --In some situations, the code constructs used may be executed in the wrong order in which the developer designed them.
+ * --For example, if you call multiple functions as part of a single expression, and the functions have the ability to modify a shared resource, then the sequence in which the resource is changed can be unpredictable.
+ * --These code snippets look suspicious and require the developer's attention.
+ * @kind problem
+ * @id cpp/errors-of-undefined-program-behavior
+ * @problem.severity warning
+ * @precision medium
+ * @tags security
+ * external/cwe/cwe-758
+ */
+
+import cpp
+import semmle.code.cpp.valuenumbering.HashCons
+import semmle.code.cpp.valuenumbering.GlobalValueNumbering
+
+/**
+ * Threatening expressions of undefined behavior.
+ */
+class ExpressionsOfTheSameLevel extends Expr {
+ Expr exp2;
+
+ ExpressionsOfTheSameLevel() {
+ this != exp2 and
+ this.getParent() = exp2.getParent()
+ }
+
+ /** Holds if the underlying expression is a function call. */
+ predicate expressionCall() {
+ this instanceof FunctionCall and
+ exp2.getAChild*() instanceof FunctionCall and
+ not this.getParent() instanceof Operator and
+ not this.(FunctionCall).hasQualifier()
+ }
+
+ /** Holds if the underlying expression is a call to a function to free resources. */
+ predicate existsCloseOrFreeCall() {
+ (
+ globalValueNumber(this.(FunctionCall).getAnArgument()) =
+ globalValueNumber(exp2.getAChild*().(FunctionCall).getAnArgument()) or
+ hashCons(this.(FunctionCall).getAnArgument()) =
+ hashCons(exp2.getAChild*().(FunctionCall).getAnArgument())
+ ) and
+ (
+ this.(FunctionCall).getTarget().hasGlobalOrStdName("close") or
+ this.(FunctionCall).getTarget().hasGlobalOrStdName("free") or
+ this.(FunctionCall).getTarget().hasGlobalOrStdName("fclose")
+ )
+ }
+
+ /** Holds if the arguments in the function can be changed. */
+ predicate generalArgumentDerivedType() {
+ exists(Parameter prt1, Parameter prt2, AssignExpr aet1, AssignExpr aet2, int i, int j |
+ not this.(FunctionCall).getArgument(i).isConstant() and
+ hashCons(this.(FunctionCall).getArgument(i)) =
+ hashCons(exp2.getAChild*().(FunctionCall).getArgument(j)) and
+ prt1 = this.(FunctionCall).getTarget().getParameter(i) and
+ prt2 = exp2.getAChild*().(FunctionCall).getTarget().getParameter(j) and
+ prt1.getType() instanceof DerivedType and
+ (
+ aet1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
+ (
+ aet1.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
+ prt1.getAnAccess().getTarget() or
+ aet1.getLValue().(VariableAccess).getTarget() = prt1.getAnAccess().getTarget()
+ )
+ or
+ exists(FunctionCall fc1 |
+ fc1.getTarget().hasGlobalName("memcpy") and
+ fc1.getArgument(0).(VariableAccess).getTarget() = prt1.getAnAccess().getTarget() and
+ fc1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
+ )
+ ) and
+ (
+ aet2 = exp2.getAChild*().(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
+ (
+ aet2.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
+ prt2.getAnAccess().getTarget() or
+ aet2.getLValue().(VariableAccess).getTarget() = prt2.getAnAccess().getTarget()
+ )
+ or
+ exists(FunctionCall fc1 |
+ fc1.getTarget().hasGlobalName("memcpy") and
+ fc1.getArgument(0).(VariableAccess).getTarget() = prt2.getAnAccess().getTarget() and
+ fc1 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
+ )
+ )
+ )
+ }
+
+ /** Holds if functions have a common global argument. */
+ predicate generalGlobalArgument() {
+ exists(Declaration dl, AssignExpr aet1, AssignExpr aet2 |
+ dl instanceof GlobalVariable and
+ (
+ (
+ aet1.getLValue().(Access).getTarget() = dl or
+ aet1.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = dl
+ ) and
+ aet1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
+ not aet1.getRValue().isConstant()
+ or
+ exists(FunctionCall fc1 |
+ fc1.getTarget().hasGlobalName("memcpy") and
+ fc1.getArgument(0).(VariableAccess).getTarget() = dl and
+ fc1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
+ )
+ ) and
+ (
+ (
+ aet2.getLValue().(Access).getTarget() = dl or
+ aet2.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = dl
+ ) and
+ aet2 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
+ or
+ exists(FunctionCall fc1 |
+ fc1.getTarget().hasGlobalName("memcpy") and
+ fc1.getArgument(0).(VariableAccess).getTarget() = dl and
+ fc1 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
+ )
+ )
+ )
+ }
+
+ /** Holds if sequence point is not present in expression. */
+ predicate orderOfActionExpressions() {
+ not this.getParent() instanceof BinaryLogicalOperation and
+ not this.getParent() instanceof ConditionalExpr and
+ not this.getParent() instanceof Loop and
+ not this.getParent() instanceof CommaExpr
+ }
+
+ /** Holds if expression is crement. */
+ predicate dangerousCrementChanges() {
+ hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2.(CrementOperation).getOperand())
+ or
+ hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2)
+ or
+ hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2.(ArrayExpr).getArrayOffset())
+ or
+ hashCons(this.(Assignment).getLValue()) = hashCons(exp2.(Assignment).getLValue())
+ or
+ not this.getAChild*() instanceof Call and
+ (
+ hashCons(this.getAChild*().(CrementOperation).getOperand()) = hashCons(exp2) or
+ hashCons(this.getAChild*().(CrementOperation).getOperand()) =
+ hashCons(exp2.(Assignment).getLValue())
+ )
+ }
+}
+
+from ExpressionsOfTheSameLevel eots
+where
+ eots.orderOfActionExpressions() and
+ (
+ eots.expressionCall() and
+ (
+ eots.generalArgumentDerivedType() or
+ eots.generalGlobalArgument() or
+ eots.existsCloseOrFreeCall()
+ )
+ or
+ eots.dangerousCrementChanges()
+ )
+select eots, "This expression may have undefined behavior."
diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll
index c2257fe294e..b2d933686d7 100644
--- a/cpp/ql/src/semmle/code/cpp/File.qll
+++ b/cpp/ql/src/semmle/code/cpp/File.qll
@@ -272,20 +272,16 @@ class File extends Container, @file {
* are compiled by a Microsoft compiler are detected by this predicate.
*/
predicate compiledAsMicrosoft() {
- exists(Compilation c |
- c.getAFileCompiled() = this and
+ exists(File f, Compilation c |
+ c.getAFileCompiled() = f and
(
c.getAnArgument() = "--microsoft" or
c.getAnArgument()
.toLowerCase()
.replaceAll("\\", "/")
.matches(["%/cl.exe", "%/clang-cl.exe"])
- )
- )
- or
- exists(File parent |
- parent.compiledAsMicrosoft() and
- parent.getAnIncludedFile() = this
+ ) and
+ f.getAnIncludedFile*() = this
)
}
@@ -358,6 +354,11 @@ class File extends Container, @file {
string getShortName() { files(underlyingElement(this), _, result, _, _) }
}
+/**
+ * Holds if any file was compiled by a Microsoft compiler.
+ */
+predicate anyFileCompiledAsMicrosoft() { any(File f).compiledAsMicrosoft() }
+
/**
* A C/C++ header file, as determined (mainly) by file extension.
*
diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll
index 8d9ad5c77e4..ef5f5511f6d 100644
--- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll
+++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll
@@ -306,7 +306,7 @@ class FormatLiteral extends Literal {
* Holds if this `FormatLiteral` is in a context that supports
* Microsoft rules and extensions.
*/
- predicate isMicrosoft() { any(File f).compiledAsMicrosoft() }
+ predicate isMicrosoft() { anyFileCompiledAsMicrosoft() }
/**
* Gets the format string, with '%%' and '%@' replaced by '_' (to avoid processing
@@ -869,6 +869,33 @@ class FormatLiteral extends Literal {
)
}
+ /**
+ * Gets an alternate argument type that would be required by the nth
+ * conversion specifier on a Microsoft or non-Microsoft platform, opposite
+ * to that of the snapshot. This may be useful for answering 'what might
+ * happen' questions.
+ */
+ Type getConversionTypeAlternate(int n) {
+ exists(string len, string conv |
+ this.parseConvSpec(n, _, _, _, _, _, len, conv) and
+ (len != "l" and len != "w" and len != "h") and
+ getUse().getTarget().(FormattingFunction).getFormatCharType().getSize() > 1 and // wide function
+ (
+ conv = "c" and
+ result = getNonDefaultCharType()
+ or
+ conv = "C" and
+ result = getDefaultCharType()
+ or
+ conv = "s" and
+ result.(PointerType).getBaseType() = getNonDefaultCharType()
+ or
+ conv = "S" and
+ result.(PointerType).getBaseType() = getDefaultCharType()
+ )
+ )
+ }
+
/**
* Holds if the nth conversion specifier of this format string (if `mode = 2`), it's
* minimum field width (if `mode = 0`) or it's precision (if `mode = 1`) requires a
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
index f6eb0a8a645..ae98b1600a1 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
@@ -208,7 +208,7 @@ private predicate bbSuccessorEntryReachesDefOrUse(
boolean skipsFirstLoopAlwaysTrueUponEntry
) {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
- bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ bbSuccessorEntryReachesLoopInvariant0(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry)
|
bbEntryReachesDefOrUseLocally(succ, v, defOrUse) and
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
index 6c50d254faa..f7b35e33f81 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
@@ -3,7 +3,250 @@
* reachability involving stack variables.
*/
-import cpp
+private import semmle.code.cpp.controlflow.Guards
+private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
+
+/** A `GuardCondition` which appear in a control-flow path to a sink. */
+abstract private class LogicalGuardCondition extends GuardCondition {
+ LogicalGuardCondition() {
+ // Either the `GuardCondition` is part of the path from a source to a sink
+ revBbSuccessorEntryReaches0(_, this.getBasicBlock(), _, _, _)
+ or
+ // or it controls the basic block that contains the source node.
+ this.controls(any(BasicBlock bb | fwdBbEntryReachesLocally(bb, _, _, _)), _)
+ }
+
+ /**
+ * Holds if the truth of this logical expression having value `wholeIsTrue`
+ * implies that the truth of the child expression `part` has truth value `partIsTrue`.
+ */
+ abstract predicate impliesCondition(
+ LogicalGuardCondition e, boolean testIsTrue, boolean condIsTrue
+ );
+}
+
+private class BinaryLogicalGuardCondition extends LogicalGuardCondition, BinaryLogicalOperation {
+ override predicate impliesCondition(
+ LogicalGuardCondition e, boolean testIsTrue, boolean condIsTrue
+ ) {
+ this.impliesValue(e, testIsTrue, condIsTrue)
+ }
+}
+
+private class VariableGuardCondition extends LogicalGuardCondition, VariableAccess {
+ override predicate impliesCondition(
+ LogicalGuardCondition e, boolean testIsTrue, boolean condIsTrue
+ ) {
+ this = e and
+ (
+ testIsTrue = true and condIsTrue = true
+ or
+ testIsTrue = false and condIsTrue = false
+ )
+ }
+}
+
+private class NotGuardCondition extends LogicalGuardCondition, NotExpr {
+ override predicate impliesCondition(
+ LogicalGuardCondition e, boolean testIsTrue, boolean condIsTrue
+ ) {
+ e = this.getOperand() and
+ (
+ testIsTrue = true and
+ condIsTrue = false
+ or
+ testIsTrue = false and
+ condIsTrue = true
+ )
+ }
+}
+
+private newtype TCondition =
+ MkCondition(LogicalGuardCondition guard, boolean testIsTrue) { testIsTrue = [false, true] }
+
+private class Condition extends MkCondition {
+ boolean testIsTrue;
+ LogicalGuardCondition guard;
+
+ Condition() { this = MkCondition(guard, testIsTrue) }
+
+ /**
+ * Holds if this condition having the value `this.getTruthValue()` implies that `cond` has truth
+ * value `cond.getTruthValue()`.
+ */
+ string toString() { result = guard.toString() + " == " + testIsTrue.toString() }
+
+ /** Gets the value of this `Condition`. */
+ boolean getTruthValue() { result = testIsTrue }
+
+ LogicalGuardCondition getCondition() { result = guard }
+
+ pragma[nomagic]
+ predicate impliesCondition(Condition cond) {
+ exists(LogicalGuardCondition other |
+ other = cond.getCondition() and
+ this.getCondition()
+ .impliesCondition(globalValueNumber(other).getAnExpr(),
+ pragma[only_bind_into](pragma[only_bind_out](testIsTrue)),
+ pragma[only_bind_into](pragma[only_bind_out](cond.getTruthValue())))
+ )
+ }
+
+ /** Gets the negated expression represented by this `Condition`, if any. */
+ private Condition negate() {
+ result.getCondition() = guard and
+ result.getTruthValue() = testIsTrue.booleanNot()
+ }
+
+ /**
+ * Holds if this condition having the value `this.getTruthValue()` implies that `cond` cannot have
+ * the truth value `cond.getTruthValue()`.
+ */
+ final predicate refutesCondition(Condition cond) { this.impliesCondition(cond.negate()) }
+
+ /** Gets the `Location` of the expression that generated this `Condition`. */
+ Location getLocation() { result = guard.getLocation() }
+}
+
+/**
+ * Gets a `Condition` that controls `b`. That is, to enter `b` the condition must hold.
+ */
+private Condition getADirectCondition(BasicBlock b) {
+ result.getCondition().controls(b, result.getTruthValue())
+}
+
+/**
+ * Like the shared dataflow library, the reachability analysis is split into two stages:
+ * In the first stage, we compute an overapproximation of the possible control-flow paths where we don't
+ * reason about path conditions. This stage is split into phases: A forward phase (computed by the
+ * predicates prefixes with `fwd`), and a reverse phase (computed by the predicates prefixed with `rev`).
+ *
+ * The forward phease computes the set of control-flow nodes reachable from a given `source` and `v` such
+ * that `config.isSource(source, v)` holds.
+ *
+ * See the QLDoc on `revBbSuccessorEntryReaches0` for a description of what the reverse phase computes.
+ */
+private predicate fwdBbSuccessorEntryReaches0(
+ ControlFlowNode source, BasicBlock bb, SemanticStackVariable v,
+ boolean skipsFirstLoopAlwaysTrueUponEntry, StackVariableReachability config
+) {
+ fwdBbEntryReachesLocally(bb, v, source, config) and
+ skipsFirstLoopAlwaysTrueUponEntry = false
+ or
+ exists(BasicBlock pred, boolean predSkipsFirstLoopAlwaysTrueUponEntry |
+ bbSuccessorEntryReachesLoopInvariant0(pred, bb, predSkipsFirstLoopAlwaysTrueUponEntry,
+ skipsFirstLoopAlwaysTrueUponEntry)
+ |
+ // Note we cannot filter out barriers at this point.
+ // See the comment in `revBbSuccessorEntryReaches0` for an explanation why,
+ fwdBbSuccessorEntryReaches0(source, pred, v, predSkipsFirstLoopAlwaysTrueUponEntry, config)
+ )
+}
+
+/**
+ * The second phase of the first stages computes, for each `source` and `v` pair such
+ * that `config.isSource(source, v)`, which sinks are reachable from that `(source, v)` pair.
+ */
+private predicate revBbSuccessorEntryReaches0(
+ ControlFlowNode source, BasicBlock bb, SemanticStackVariable v,
+ boolean skipsFirstLoopAlwaysTrueUponEntry, StackVariableReachability config
+) {
+ exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
+ fwdBbSuccessorEntryReaches0(source, bb, v, skipsFirstLoopAlwaysTrueUponEntry, config) and
+ bbSuccessorEntryReachesLoopInvariant0(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ succSkipsFirstLoopAlwaysTrueUponEntry)
+ |
+ revBbEntryReachesLocally(succ, v, _, config) and
+ succSkipsFirstLoopAlwaysTrueUponEntry = false
+ or
+ // Note: We cannot rule out a successor block that contain a barrier here (like we do later in
+ // `bbSuccessorEntryReaches`) as we might later discover that the only way to get through a piece of
+ // code is through that barrier, and we want to discover this in
+ // `bbSuccessorEntryReachesLoopInvariant`. As an example, consider this piece of code:
+ // ```
+ // if(b) { (1) source(); }
+ // (2) if(b) { (3) barrier(); }
+ // (4) sink();
+ // ```
+ // here, we want the successor relation to contain:
+ // 1 -> {2}, 2 -> {3, 4}
+ // since the second stage will deduce that the edge (2) -> (3) is unconditional (as b is always true
+ // if we start at `source()`), and so there is actually no path from (1) to (4) without going through
+ // a barrier.
+ revBbSuccessorEntryReaches0(source, succ, v, succSkipsFirstLoopAlwaysTrueUponEntry, config)
+ )
+}
+
+private predicate successorExitsLoop(BasicBlock pred, BasicBlock succ, Loop loop) {
+ pred.getASuccessor() = succ and
+ bbDominates(loop.getStmt(), pred) and
+ not bbDominates(loop.getStmt(), succ)
+}
+
+private predicate successorExitsFirstDisjunct(BasicBlock pred, BasicBlock succ) {
+ exists(LogicalOrExpr orExpr | orExpr instanceof GuardCondition |
+ pred.getAFalseSuccessor() = succ and
+ pred.contains(orExpr.getLeftOperand())
+ )
+}
+
+/**
+ * When we exit a loop, we filter out the conditions that arise from the loop's guard.
+ * To see why this is necessary, consider this example:
+ * ```
+ * (1) source();
+ * while (b) { (2) ... }
+ * (3) sink();
+ * ```
+ * If we keep all the conditions when we transition from (2) to (3) we learn that `b` is true at
+ * (3), but since we exited the loop we also learn that `b` is false at 3.
+ * Thus, when we transition from (2) to (3) we discard all those conditions that are true at (2),
+ * but NOT true at (3).
+ */
+private predicate isLoopCondition(LogicalGuardCondition cond, BasicBlock pred, BasicBlock bb) {
+ exists(Loop loop, boolean testIsTrue | successorExitsLoop(pred, bb, loop) |
+ // the resulting `Condition` holds inside the loop
+ cond.controls(pred, testIsTrue) and
+ // but not prior to the loop.
+ not cond.controls(loop.getBasicBlock(), testIsTrue)
+ )
+}
+
+/**
+ * When we leave the first disjunct we throw away the condition that says the the first disjunct is
+ * false. To see why this is necessary, consider this example:
+ * ```
+ * if((1) b1 || (2) b2) { (3) ... }
+ * ```
+ * it holds that `b1 == false` controls (2), and since (2) steps to (3) we learn that `b1 == false `
+ * holds at (3). So we filter out the conditions that we learn from leaving taking the false
+ * branch in a disjunction.
+ */
+private predicate isDisjunctionCondition(LogicalGuardCondition cond, BasicBlock pred, BasicBlock bb) {
+ exists(boolean testIsTrue | successorExitsFirstDisjunct(pred, bb) |
+ // the resulting `Condition` holds after evaluating the left-hand side
+ cond.controls(bb, testIsTrue) and
+ // but not before evaluating the left-hand side.
+ not cond.controls(pred, testIsTrue)
+ )
+}
+
+private predicate isLoopVariantCondition(LogicalGuardCondition cond, BasicBlock pred, BasicBlock bb) {
+ exists(Loop loop |
+ bb.getEnd() = loop.getCondition() and
+ pred.getASuccessor() = bb and
+ bbDominates(bb, pred) and
+ loopVariant(cond.getAChild*(), loop)
+ )
+}
+
+private predicate loopVariant(VariableAccess e, Loop loop) {
+ exists(SsaDefinition d | d.getAUse(e.getTarget()) = e |
+ d.getAnUltimateDefiningValue(e.getTarget()) = loop.getCondition().getAChild*() or
+ d.getAnUltimateDefiningValue(e.getTarget()).getEnclosingStmt().getParent*() = loop.getStmt() or
+ d.getAnUltimateDefiningValue(e.getTarget()) = loop.(ForStmt).getUpdate().getAChild*()
+ )
+}
/**
* A reachability analysis for control-flow nodes involving stack variables.
@@ -60,7 +303,8 @@ abstract class StackVariableReachability extends string {
* ```
*
* In addition to using a better performing implementation, this analysis
- * accounts for loops where the condition is provably true upon entry.
+ * accounts for loops where the condition is provably true upon entry, and discards paths that require
+ * an infeasible combination of guard conditions (for example, `if(b) { ... }` and `if(!b) { ... }`).
*/
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
/*
@@ -80,46 +324,184 @@ abstract class StackVariableReachability extends string {
j > i and
sink = bb.getNode(j) and
isSink(sink, v) and
- not exists(int k | isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
+ not isBarrier(bb.getNode(pragma[only_bind_into]([i + 1 .. j - 1])), v)
)
or
not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and
- bbSuccessorEntryReaches(bb, v, sink, _)
+ bbSuccessorEntryReaches(source, bb, v, sink, _)
+ )
+ }
+
+ private Condition getASinkCondition(SemanticStackVariable v) {
+ exists(BasicBlock bb |
+ revBbEntryReachesLocally(bb, v, _, this) and
+ result.getCondition().controls(bb, result.getTruthValue())
+ )
+ }
+
+ private Condition getABarrierCondition(SemanticStackVariable v) {
+ exists(BasicBlock bb |
+ isBarrier(bb.getANode(), v) and
+ result.getCondition().controls(bb, result.getTruthValue())
+ )
+ }
+
+ /**
+ * Gets a condition with a known truth value in `bb` when the control-flow starts at the source
+ * node `source` and we're tracking reachability using variable `v` (that is,
+ * `this.isSource(source, v)` holds).
+ *
+ * This predicate is `pragma[noopt]` as it seems difficult to get the correct join order for the
+ * recursive case otherwise:
+ * revBbSuccessorEntryReaches0(bb) -> getASuccessor -> prev_delta ->
+ * revBbSuccessorEntryReaches0(pred) -> {isLoopCondition, isDisjunctionCondition, isLoopVariantCondition}
+ */
+ pragma[noopt]
+ private Condition getACondition(ControlFlowNode source, SemanticStackVariable v, BasicBlock bb) {
+ revBbSuccessorEntryReaches0(source, bb, v, _, this) and
+ (
+ result = getADirectCondition(bb) and
+ (
+ exists(Condition c |
+ c = getASinkCondition(v) and
+ result.refutesCondition(c)
+ )
+ or
+ exists(Condition c |
+ c = getABarrierCondition(v) and
+ result.impliesCondition(c)
+ )
+ )
+ or
+ exists(BasicBlock pred |
+ pred.getASuccessor() = bb and
+ result = getACondition(source, v, pred) and
+ revBbSuccessorEntryReaches0(source, pred, v, _, this) and
+ exists(LogicalGuardCondition c | c = result.getCondition() |
+ not isLoopCondition(c, pred, bb) and
+ not isDisjunctionCondition(c, pred, bb) and
+ not isLoopVariantCondition(c, pred, bb)
+ )
+ )
+ )
+ }
+
+ pragma[nomagic]
+ private predicate bbSuccessorEntryReachesLoopInvariantSucc(
+ ControlFlowNode source, BasicBlock pred, SemanticStackVariable v, BasicBlock succ,
+ boolean predSkipsFirstLoopAlwaysTrueUponEntry
+ ) {
+ revBbSuccessorEntryReaches0(source, pragma[only_bind_into](pred), v,
+ predSkipsFirstLoopAlwaysTrueUponEntry, this) and
+ pred.getASuccessor() = succ
+ }
+
+ pragma[nomagic]
+ private predicate bbSuccessorEntryReachesLoopInvariantCand(
+ ControlFlowNode source, BasicBlock pred, SemanticStackVariable v, BasicBlock succ,
+ boolean predSkipsFirstLoopAlwaysTrueUponEntry, boolean succSkipsFirstLoopAlwaysTrueUponEntry
+ ) {
+ bbSuccessorEntryReachesLoopInvariantSucc(source, pragma[only_bind_into](pred), v, succ,
+ predSkipsFirstLoopAlwaysTrueUponEntry) and
+ bbSuccessorEntryReachesLoopInvariant0(pred, succ, predSkipsFirstLoopAlwaysTrueUponEntry,
+ succSkipsFirstLoopAlwaysTrueUponEntry)
+ }
+
+ /**
+ * Holds if `pred`, `succ`, `predSkipsFirstLoopAlwaysTrueUponEntry` and
+ * `succSkipsFirstLoopAlwaysTrueUponEntry` satisfy the loop invariants specified in the QLDoc
+ * for `bbSuccessorEntryReachesLoopInvariant0`.
+ *
+ * In addition, this predicate:
+ * 1. Rules out successor blocks that are unreachable due to contradictory path conditions.
+ * 2. Refines the successor relation when the edge `pred -> succ` is a conditional edge whose truth
+ * value is known.
+ */
+ pragma[nomagic]
+ private predicate bbSuccessorEntryReachesLoopInvariant(
+ ControlFlowNode source, BasicBlock pred, SemanticStackVariable v, BasicBlock succ,
+ boolean predSkipsFirstLoopAlwaysTrueUponEntry, boolean succSkipsFirstLoopAlwaysTrueUponEntry
+ ) {
+ bbSuccessorEntryReachesLoopInvariantCand(source, pred, v, succ,
+ predSkipsFirstLoopAlwaysTrueUponEntry, succSkipsFirstLoopAlwaysTrueUponEntry) and
+ not exists(Condition cond, Condition direct |
+ cond = getACondition(source, v, pred) and
+ direct = pragma[only_bind_out](getADirectCondition(succ)) and
+ cond.refutesCondition(direct)
+ ) and
+ (
+ // If we picked the successor edge corresponding to a condition being true, there must not be
+ // another path condition that refutes that the condition is true.
+ not exists(Condition cond | cond = getACondition(source, v, pred) |
+ succ = pred.getATrueSuccessor() and
+ cond.refutesCondition(pragma[only_bind_out](MkCondition(pred.getEnd(), true)))
+ ) and
+ // If we picked the successor edge corresponding to a condition being false, there must not be
+ // another path condition that refutes that the condition is false.
+ not exists(Condition cond | cond = getACondition(source, v, pred) |
+ succ = pred.getAFalseSuccessor() and
+ cond.refutesCondition(pragma[only_bind_out](MkCondition(pred.getEnd(), false)))
+ )
)
}
private predicate bbSuccessorEntryReaches(
- BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
+ ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
boolean skipsFirstLoopAlwaysTrueUponEntry
) {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
- bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ bbSuccessorEntryReachesLoopInvariant(source, bb, v, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry)
|
- bbEntryReachesLocally(succ, v, node) and
+ revBbEntryReachesLocally(succ, v, node, this) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
- not isBarrier(succ.getNode(_), v) and
- bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
+ bbSuccessorEntryReachesLoopInvariant(source, bb, v, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ succSkipsFirstLoopAlwaysTrueUponEntry) and
+ not isBarrier(pragma[only_bind_out](succ.getANode()), v) and
+ pragma[only_bind_into](this)
+ .bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
)
}
+}
- private predicate bbEntryReachesLocally(
- BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
- ) {
- exists(int n |
- node = bb.getNode(n) and
- isSink(node, v)
- |
- not exists(this.firstBarrierIndexIn(bb, v))
+private predicate fwdBbEntryReachesLocally(
+ BasicBlock bb, SemanticStackVariable v, ControlFlowNode node, StackVariableReachability config
+) {
+ exists(int n |
+ node = bb.getNode(n) and
+ config.isSource(node, v) and
+ (
+ not exists(lastBarrierIndexIn(bb, v, config))
or
- n <= this.firstBarrierIndexIn(bb, v)
+ lastBarrierIndexIn(bb, v, config) <= n
)
- }
+ )
+}
- private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
- result = min(int m | isBarrier(bb.getNode(m), v))
- }
+private predicate revBbEntryReachesLocally(
+ BasicBlock bb, SemanticStackVariable v, ControlFlowNode node, StackVariableReachability config
+) {
+ exists(int n |
+ node = bb.getNode(n) and
+ config.isSink(node, v)
+ |
+ not exists(firstBarrierIndexIn(bb, v, config))
+ or
+ n <= firstBarrierIndexIn(bb, v, config)
+ )
+}
+
+private int firstBarrierIndexIn(
+ BasicBlock bb, SemanticStackVariable v, StackVariableReachability config
+) {
+ result = min(int m | config.isBarrier(bb.getNode(m), v))
+}
+
+private int lastBarrierIndexIn(
+ BasicBlock bb, SemanticStackVariable v, StackVariableReachability config
+) {
+ result = max(int m | config.isBarrier(bb.getNode(m), v))
}
/**
@@ -182,7 +564,7 @@ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
* is provably true upon entry, then `succ` is not allowed to skip
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
*/
-predicate bbSuccessorEntryReachesLoopInvariant(
+predicate bbSuccessorEntryReachesLoopInvariant0(
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
boolean succSkipsFirstLoopAlwaysTrueUponEntry
) {
@@ -296,10 +678,52 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe
)
}
+ private predicate bbSuccessorEntryReaches(
+ BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
+ boolean skipsFirstLoopAlwaysTrueUponEntry
+ ) {
+ exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
+ bbSuccessorEntryReachesLoopInvariant0(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ succSkipsFirstLoopAlwaysTrueUponEntry)
+ |
+ revBbEntryReachesLocally(succ, v, node, this) and
+ succSkipsFirstLoopAlwaysTrueUponEntry = false
+ or
+ not isBarrier(succ.getNode(_), v) and
+ bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
+ )
+ }
+
+ private predicate reaches0(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
+ /*
+ * Implementation detail: the predicates in this class are a generalization of
+ * those in DefinitionsAndUses.qll, and should be kept in sync.
+ *
+ * Unfortunately, caching of abstract predicates does not work well, so the
+ * predicates in DefinitionsAndUses.qll cannot use this library.
+ */
+
+ exists(BasicBlock bb, int i |
+ isSource(source, v) and
+ bb.getNode(i) = source and
+ not bb.isUnreachable()
+ |
+ exists(int j |
+ j > i and
+ sink = bb.getNode(j) and
+ isSink(sink, v) and
+ not isBarrier(bb.getNode(pragma[only_bind_into]([i + 1 .. j - 1])), v)
+ )
+ or
+ not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and
+ bbSuccessorEntryReaches(bb, v, sink, _)
+ )
+ }
+
private predicate reassignment(
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
) {
- StackVariableReachability.super.reaches(source, v, def) and
+ reaches0(source, v, def) and
exprDefinition(v0, def, v.getAnAccess())
}
@@ -365,11 +789,11 @@ abstract class StackVariableReachabilityExt extends string {
boolean skipsFirstLoopAlwaysTrueUponEntry
) {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
- bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
+ bbSuccessorEntryReachesLoopInvariant0(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry) and
not isBarrier(source, bb.getEnd(), succ.getStart(), v)
|
- bbEntryReachesLocally(source, succ, v, node) and
+ this.bbEntryReachesLocally(source, succ, v, node) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
not exists(int k | isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
index 462e89ac9ed..728f7b56c42 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
@@ -724,7 +724,6 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
- read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
@@ -1118,6 +1117,44 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
}
+/**
+ * Checks whether `inner` can return to `call` in the call context `innercc`.
+ * Assumes a context of `inner = viableCallableExt(call)`.
+ */
+bindingset[innercc, inner, call]
+predicate checkCallContextReturn(CallContext innercc, DataFlowCallable inner, DataFlowCall call) {
+ innercc instanceof CallContextAny
+ or
+ exists(DataFlowCallable c0, DataFlowCall call0 |
+ callEnclosingCallable(call0, inner) and
+ innercc = TReturn(c0, call0) and
+ c0 = prunedViableImplInCallContextReverse(call0, call)
+ )
+}
+
+/**
+ * Checks whether `call` can resolve to `calltarget` in the call context `cc`.
+ * Assumes a context of `calltarget = viableCallableExt(call)`.
+ */
+bindingset[cc, call, calltarget]
+predicate checkCallContextCall(CallContext cc, DataFlowCall call, DataFlowCallable calltarget) {
+ exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
+ if reducedViableImplInCallContext(call, _, ctx)
+ then calltarget = prunedViableImplInCallContext(call, ctx)
+ else any()
+ )
+ or
+ cc instanceof CallContextSomeCall
+ or
+ cc instanceof CallContextAny
+ or
+ cc instanceof CallContextReturn
+}
+
+/**
+ * Resolves a return from `callable` in `cc` to `call`. This is equivalent to
+ * `callable = viableCallableExt(call) and checkCallContextReturn(cc, callable, call)`.
+ */
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallableExt(call)
@@ -1129,6 +1166,10 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
)
}
+/**
+ * Resolves a call from `call` in `cc` to `result`. This is equivalent to
+ * `result = viableCallableExt(call) and checkCallContextCall(cc, call, result)`.
+ */
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll
index cb0ae4490f8..e64f8277528 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll
@@ -133,46 +133,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
-private newtype TContent =
- TFieldContent(Field f) or
- TCollectionContent() or
- TArrayContent()
-
-/**
- * A reference contained in an object. Examples include instance fields, the
- * contents of a collection object, or the contents of an array.
- */
-class Content extends TContent {
- /** Gets a textual representation of this element. */
- abstract string toString();
-
- predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
- path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
- }
-}
-
-private class FieldContent extends Content, TFieldContent {
- Field f;
-
- FieldContent() { this = TFieldContent(f) }
-
- Field getField() { result = f }
-
- override string toString() { result = f.toString() }
-
- override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
- f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
- }
-}
-
-private class CollectionContent extends Content, TCollectionContent {
- override string toString() { result = "collection" }
-}
-
-private class ArrayContent extends Content, TArrayContent {
- override string toString() { result = "array" }
-}
-
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
index 5db9a84c80a..0d723ac05b6 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
@@ -768,6 +768,50 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) {
)
}
+private newtype TContent =
+ TFieldContent(Field f) or
+ TCollectionContent() or
+ TArrayContent()
+
+/**
+ * A description of the way data may be stored inside an object. Examples
+ * include instance fields, the contents of a collection object, or the contents
+ * of an array.
+ */
+class Content extends TContent {
+ /** Gets a textual representation of this element. */
+ abstract string toString();
+
+ predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
+ path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
+ }
+}
+
+/** A reference through an instance field. */
+class FieldContent extends Content, TFieldContent {
+ Field f;
+
+ FieldContent() { this = TFieldContent(f) }
+
+ Field getField() { result = f }
+
+ override string toString() { result = f.toString() }
+
+ override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
+ f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
+ }
+}
+
+/** A reference through an array. */
+private class ArrayContent extends Content, TArrayContent {
+ override string toString() { result = "[]" }
+}
+
+/** A reference through the contents of some collection-like container. */
+private class CollectionContent extends Content, TCollectionContent {
+ override string toString() { result = "" }
+}
+
/**
* A guard that validates some expression.
*
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
index 6216045db32..eae16081974 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
@@ -34,6 +34,13 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
+/**
+ * Holds if default `TaintTracking::Configuration`s should allow implicit reads
+ * of `c` at sinks and inputs to additional taint steps.
+ */
+bindingset[node]
+predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
+
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
index 99d8555f8ca..4ebd8cbf758 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
@@ -231,10 +231,35 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
-predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() }
+predicate mayBenefitFromCallContext(CallInstruction call, Function f) {
+ mayBenefitFromCallContext(call, f, _)
+}
+
+/**
+ * Holds if `call` is a call through a function pointer, and the pointer
+ * value is given as the `arg`'th argument to `f`.
+ */
+private predicate mayBenefitFromCallContext(
+ VirtualDispatch::DataSensitiveCall call, Function f, int arg
+) {
+ f = pragma[only_bind_out](call).getEnclosingCallable() and
+ exists(InitializeParameterInstruction init |
+ not exists(call.getStaticCallTarget()) and
+ init.getEnclosingFunction() = f and
+ call.flowsFrom(DataFlow::instructionNode(init), _) and
+ init.getParameter().getIndex() = arg
+ )
+}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
-Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() }
+Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
+ result = viableCallable(call) and
+ exists(int i, Function f |
+ mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
+ f = ctx.getStaticCallTarget() and
+ result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
+ )
+}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
index 462e89ac9ed..728f7b56c42 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
@@ -724,7 +724,6 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
- read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
@@ -1118,6 +1117,44 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
}
+/**
+ * Checks whether `inner` can return to `call` in the call context `innercc`.
+ * Assumes a context of `inner = viableCallableExt(call)`.
+ */
+bindingset[innercc, inner, call]
+predicate checkCallContextReturn(CallContext innercc, DataFlowCallable inner, DataFlowCall call) {
+ innercc instanceof CallContextAny
+ or
+ exists(DataFlowCallable c0, DataFlowCall call0 |
+ callEnclosingCallable(call0, inner) and
+ innercc = TReturn(c0, call0) and
+ c0 = prunedViableImplInCallContextReverse(call0, call)
+ )
+}
+
+/**
+ * Checks whether `call` can resolve to `calltarget` in the call context `cc`.
+ * Assumes a context of `calltarget = viableCallableExt(call)`.
+ */
+bindingset[cc, call, calltarget]
+predicate checkCallContextCall(CallContext cc, DataFlowCall call, DataFlowCallable calltarget) {
+ exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
+ if reducedViableImplInCallContext(call, _, ctx)
+ then calltarget = prunedViableImplInCallContext(call, ctx)
+ else any()
+ )
+ or
+ cc instanceof CallContextSomeCall
+ or
+ cc instanceof CallContextAny
+ or
+ cc instanceof CallContextReturn
+}
+
+/**
+ * Resolves a return from `callable` in `cc` to `call`. This is equivalent to
+ * `callable = viableCallableExt(call) and checkCallContextReturn(cc, callable, call)`.
+ */
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallableExt(call)
@@ -1129,6 +1166,10 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
)
}
+/**
+ * Resolves a call from `call` in `cc` to `result`. This is equivalent to
+ * `result = viableCallableExt(call) and checkCallContextCall(cc, call, result)`.
+ */
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index 43b82f4d517..73bf72a3643 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -184,64 +184,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
-/**
- * Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
- */
-private Field getAField(Class c, int startBit, int endBit) {
- result.getDeclaringType() = c and
- startBit = 8 * result.getByteOffset() and
- endBit = 8 * result.getType().getSize() + startBit
- or
- exists(Field f, Class cInner |
- f = c.getAField() and
- cInner = f.getUnderlyingType() and
- result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
- )
-}
-
-private newtype TContent =
- TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
- TCollectionContent() or
- TArrayContent()
-
-/**
- * A reference contained in an object. Examples include instance fields, the
- * contents of a collection object, or the contents of an array.
- */
-class Content extends TContent {
- /** Gets a textual representation of this element. */
- abstract string toString();
-
- predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
- path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
- }
-}
-
-private class FieldContent extends Content, TFieldContent {
- Class c;
- int startBit;
- int endBit;
-
- FieldContent() { this = TFieldContent(c, startBit, endBit) }
-
- // Ensure that there's just 1 result for `toString`.
- override string toString() { result = min(Field f | f = getAField() | f.toString()) }
-
- predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
-
- Field getAField() { result = getAField(c, startBit, endBit) }
-}
-
-private class CollectionContent extends Content, TCollectionContent {
- override string toString() { result = "collection" }
-}
-
-private class ArrayContent extends Content, TArrayContent {
- ArrayContent() { this = TArrayContent() }
-
- override string toString() { result = "array content" }
-}
-
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(StoreInstruction store, Class c |
store = node2.asInstruction() and
@@ -288,7 +230,7 @@ private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode n
}
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
- a = TArrayContent() and
+ exists(a) and
exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store |
chi.getPartialOperand() = operand and
store = operand.getDef() and
@@ -383,7 +325,7 @@ private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
*/
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
- a = TArrayContent() and
+ exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
node1.asInstruction() = write and
node2.asInstruction() = chi and
@@ -412,7 +354,7 @@ private Instruction skipCopyValueInstructions(Operand op) {
}
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
- a = TArrayContent() and
+ exists(a) and
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
exists(LoadOperand operand, Instruction address |
operand.isDefinitionInexact() and
@@ -443,7 +385,7 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
* from the access path.
*/
private predicate exactReadStep(Node node1, ArrayContent a, Node node2) {
- a = TArrayContent() and
+ exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
not chi.isResultConflated() and
chi.getPartial() = write and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 915f51b4576..bf21249d4ca 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -788,6 +788,66 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
*/
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
+/**
+ * Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
+ */
+private Field getAField(Class c, int startBit, int endBit) {
+ result.getDeclaringType() = c and
+ startBit = 8 * result.getByteOffset() and
+ endBit = 8 * result.getType().getSize() + startBit
+ or
+ exists(Field f, Class cInner |
+ f = c.getAField() and
+ cInner = f.getUnderlyingType() and
+ result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
+ )
+}
+
+private newtype TContent =
+ TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
+ TCollectionContent() or
+ TArrayContent()
+
+/**
+ * A description of the way data may be stored inside an object. Examples
+ * include instance fields, the contents of a collection object, or the contents
+ * of an array.
+ */
+class Content extends TContent {
+ /** Gets a textual representation of this element. */
+ abstract string toString();
+
+ predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
+ path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
+ }
+}
+
+/** A reference through an instance field. */
+class FieldContent extends Content, TFieldContent {
+ Class c;
+ int startBit;
+ int endBit;
+
+ FieldContent() { this = TFieldContent(c, startBit, endBit) }
+
+ // Ensure that there's just 1 result for `toString`.
+ override string toString() { result = min(Field f | f = getAField() | f.toString()) }
+
+ predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
+
+ Field getAField() { result = getAField(c, startBit, endBit) }
+}
+
+/** A reference through an array. */
+class ArrayContent extends Content, TArrayContent {
+ override string toString() { result = "[]" }
+}
+
+/** A reference through the contents of some collection-like container. */
+private class CollectionContent extends Content, TCollectionContent {
+ override string toString() { result = "" }
+}
+
/**
* A guard that validates some instruction.
*
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
index ab1177daea9..f563e47db9f 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
@@ -151,6 +151,13 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
+/**
+ * Holds if default `TaintTracking::Configuration`s should allow implicit reads
+ * of `c` at sinks and inputs to additional taint steps.
+ */
+bindingset[node]
+predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
+
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll
index 885a1adc3ad..9630bb13e18 100644
--- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll
+++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll
@@ -50,7 +50,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
* Holds if this `FormattingFunction` is in a context that supports
* Microsoft rules and extensions.
*/
- predicate isMicrosoft() { any(File f).compiledAsMicrosoft() }
+ predicate isMicrosoft() { anyFileCompiledAsMicrosoft() }
/**
* Holds if the default meaning of `%s` is a `wchar_t *`, rather than
diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
index 79dbe49611e..187641559f4 100644
--- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
@@ -863,16 +863,16 @@ private float getLowerBoundsImpl(Expr expr) {
result = 0
or
// If either input could be negative then the output could be
- // negative. If so, the lower bound of `x%y` is `-abs(y)`, which is
- // equal to `min(-y,y)`.
+ // negative. If so, the lower bound of `x%y` is `-abs(y) + 1`, which is
+ // equal to `min(-y + 1,y - 1)`.
exists(float childLB |
childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and
not childLB >= 0
|
- result = getFullyConvertedLowerBounds(remExpr.getRightOperand())
+ result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1
or
exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) |
- result = -rhsUB
+ result = -rhsUB + 1
)
)
)
@@ -1058,16 +1058,16 @@ private float getUpperBoundsImpl(Expr expr) {
expr = remExpr and
rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand())
|
- result = rhsUB
+ result = rhsUB - 1
or
// If the right hand side could be negative then we need to take its
// absolute value. Since `abs(x) = max(-x,x)` this is equivalent to
// adding `-rhsLB` to the set of upper bounds.
exists(float rhsLB |
- rhsLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and
+ rhsLB = getFullyConvertedLowerBounds(remExpr.getRightOperand()) and
not rhsLB >= 0
|
- result = -rhsLB
+ result = -rhsLB + 1
)
)
or
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.expected
new file mode 100644
index 00000000000..43ac03030dd
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.expected
@@ -0,0 +1,3 @@
+| test.c:13:10:13:21 | call to tmpFunction1 | This expression may have undefined behavior. |
+| test.c:13:30:13:41 | call to tmpFunction2 | This expression may have undefined behavior. |
+| test.c:16:15:16:20 | ... ++ | This expression may have undefined behavior. |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.qlref
new file mode 100644
index 00000000000..e178bc348e9
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/UndefinedOrImplementationDefinedBehavior.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.ql
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/test.c
new file mode 100644
index 00000000000..01d8e666cdd
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-758/semmle/tests/test.c
@@ -0,0 +1,19 @@
+char tmpFunction1(char * buf)
+{
+ buf[1]=buf[1] + buf[2] + buf[3];
+ return buf[1];
+}
+char tmpFunction2(char * buf)
+{
+ buf[2]=buf[1] + buf[2] + buf[3];
+ return buf[2];
+}
+void workFunction_0(char *s, char * buf) {
+ int intA;
+ intA = tmpFunction1(buf) + tmpFunction2(buf); // BAD
+ intA = tmpFunction1(buf); //GOOD
+ intA += tmpFunction2(buf); // GOOD
+ buf[intA] = intA++; // BAD
+ intA++;
+ buf[intA] = intA; // GOOD
+}
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
index ee6b6a39bde..2736cdcd9e1 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
@@ -58,29 +58,29 @@ edges
| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] |
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Chi [m1] |
| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] |
-| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [array content] |
-| aliasing.cpp:121:15:121:16 | Chi [array content] | aliasing.cpp:122:8:122:12 | access to array |
-| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | aliasing.cpp:121:15:121:16 | Chi [array content] |
-| aliasing.cpp:131:15:131:16 | Chi [array content] | aliasing.cpp:132:8:132:14 | * ... |
-| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | aliasing.cpp:131:15:131:16 | Chi [array content] |
-| aliasing.cpp:136:15:136:17 | Chi [array content] | aliasing.cpp:137:8:137:11 | * ... |
-| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | aliasing.cpp:136:15:136:17 | Chi [array content] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] |
+| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [[]] |
+| aliasing.cpp:121:15:121:16 | Chi [[]] | aliasing.cpp:122:8:122:12 | access to array |
+| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] | aliasing.cpp:121:15:121:16 | Chi [[]] |
+| aliasing.cpp:131:15:131:16 | Chi [[]] | aliasing.cpp:132:8:132:14 | * ... |
+| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] | aliasing.cpp:131:15:131:16 | Chi [[]] |
+| aliasing.cpp:136:15:136:17 | Chi [[]] | aliasing.cpp:137:8:137:11 | * ... |
+| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] | aliasing.cpp:136:15:136:17 | Chi [[]] |
| aliasing.cpp:175:15:175:22 | Chi | aliasing.cpp:175:15:175:22 | Chi [m1] |
| aliasing.cpp:175:15:175:22 | Chi [m1] | aliasing.cpp:176:13:176:14 | m1 |
-| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | Chi |
+| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] | aliasing.cpp:175:15:175:22 | Chi |
| aliasing.cpp:187:15:187:22 | Chi | aliasing.cpp:187:15:187:22 | Chi [m1] |
| aliasing.cpp:187:15:187:22 | Chi [m1] | aliasing.cpp:188:13:188:14 | Store [m1] |
-| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | Chi |
+| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] | aliasing.cpp:187:15:187:22 | Chi |
| aliasing.cpp:188:13:188:14 | Store [m1] | aliasing.cpp:189:15:189:16 | m1 |
| aliasing.cpp:200:15:200:24 | Chi | aliasing.cpp:200:15:200:24 | Chi [m1] |
| aliasing.cpp:200:15:200:24 | Chi [m1] | aliasing.cpp:201:15:201:16 | m1 |
-| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | Chi |
+| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] | aliasing.cpp:200:15:200:24 | Chi |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
@@ -108,32 +108,32 @@ edges
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] |
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] |
-| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] |
-| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] |
-| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [array content] |
-| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] |
-| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] |
-| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] |
+| by_reference.cpp:92:3:92:20 | Chi [[]] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] |
+| by_reference.cpp:92:3:92:20 | Chi [[]] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] |
+| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [[]] |
+| by_reference.cpp:96:3:96:19 | Chi [[]] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] |
+| by_reference.cpp:96:3:96:19 | Chi [[]] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] |
+| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [[]] |
| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a |
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] |
| by_reference.cpp:104:15:104:22 | Chi | by_reference.cpp:104:15:104:22 | Chi [a] |
| by_reference.cpp:104:15:104:22 | Chi [a] | by_reference.cpp:112:14:112:14 | a |
-| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | Chi |
+| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] | by_reference.cpp:104:15:104:22 | Chi |
| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a |
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] |
| by_reference.cpp:108:15:108:24 | Chi | by_reference.cpp:108:15:108:24 | Chi [a] |
| by_reference.cpp:108:15:108:24 | Chi [a] | by_reference.cpp:116:16:116:16 | a |
-| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | Chi |
+| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] | by_reference.cpp:108:15:108:24 | Chi |
| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a |
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] |
| by_reference.cpp:124:15:124:21 | Chi | by_reference.cpp:124:15:124:21 | Chi [a] |
| by_reference.cpp:124:15:124:21 | Chi [a] | by_reference.cpp:132:14:132:14 | a |
-| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | Chi |
+| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] | by_reference.cpp:124:15:124:21 | Chi |
| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a |
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] |
| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] |
| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a |
-| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | Chi |
+| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] | by_reference.cpp:128:15:128:23 | Chi |
| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:16:42:16 | f indirection [a_] |
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | f indirection [b_] |
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:16:43:16 | f indirection [b_] |
@@ -304,29 +304,29 @@ nodes
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
-| aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] |
+| aliasing.cpp:106:3:106:20 | Chi [[]] | semmle.label | Chi [[]] |
| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input |
-| aliasing.cpp:121:15:121:16 | Chi [array content] | semmle.label | Chi [array content] |
-| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:121:15:121:16 | Chi [[]] | semmle.label | Chi [[]] |
+| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:122:8:122:12 | access to array | semmle.label | access to array |
-| aliasing.cpp:131:15:131:16 | Chi [array content] | semmle.label | Chi [array content] |
-| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:131:15:131:16 | Chi [[]] | semmle.label | Chi [[]] |
+| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:132:8:132:14 | * ... | semmle.label | * ... |
-| aliasing.cpp:136:15:136:17 | Chi [array content] | semmle.label | Chi [array content] |
-| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:136:15:136:17 | Chi [[]] | semmle.label | Chi [[]] |
+| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:137:8:137:11 | * ... | semmle.label | * ... |
| aliasing.cpp:175:15:175:22 | Chi | semmle.label | Chi |
| aliasing.cpp:175:15:175:22 | Chi [m1] | semmle.label | Chi [m1] |
-| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 |
| aliasing.cpp:187:15:187:22 | Chi | semmle.label | Chi |
| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [m1] |
-| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 |
| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi |
| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] |
-| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 |
| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array |
@@ -360,20 +360,20 @@ nodes
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
-| by_reference.cpp:92:3:92:20 | Chi [array content] | semmle.label | Chi [array content] |
+| by_reference.cpp:92:3:92:20 | Chi [[]] | semmle.label | Chi [[]] |
| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input |
-| by_reference.cpp:96:3:96:19 | Chi [array content] | semmle.label | Chi [array content] |
+| by_reference.cpp:96:3:96:19 | Chi [[]] | semmle.label | Chi [[]] |
| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
| by_reference.cpp:104:15:104:22 | Chi | semmle.label | Chi |
| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [a] |
-| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi |
| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] |
-| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
+| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
| by_reference.cpp:112:14:112:14 | a | semmle.label | a |
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
@@ -382,12 +382,12 @@ nodes
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
| by_reference.cpp:124:15:124:21 | Chi | semmle.label | Chi |
| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [a] |
-| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] |
+| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] | semmle.label | taint_a_ref output argument [[]] |
| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi |
| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] |
-| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] |
+| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] | semmle.label | taint_a_ref output argument [[]] |
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
| by_reference.cpp:132:14:132:14 | a | semmle.label | a |
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
diff --git a/cpp/ql/test/library-tests/fields/fields/Fields.expected b/cpp/ql/test/library-tests/fields/fields/Fields.expected
index 6ef4a17ec50..a4cb4e549cc 100644
--- a/cpp/ql/test/library-tests/fields/fields/Fields.expected
+++ b/cpp/ql/test/library-tests/fields/fields/Fields.expected
@@ -1,13 +1,21 @@
| fields.cpp:3:8:3:12 | Entry | fields.cpp:4:9:4:12 | name | public | CharPointerType | char |
+| fields.cpp:3:8:3:12 | Entry | fields.cpp:4:9:4:12 | name | public | PointerDumpType | char |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:5:8:5:8 | t | public | Enum | |
+| fields.cpp:3:8:3:12 | Entry | fields.cpp:5:8:5:8 | t | public | UserDumpType | |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:6:9:6:9 | s | public | CharPointerType | char |
+| fields.cpp:3:8:3:12 | Entry | fields.cpp:6:9:6:9 | s | public | PointerDumpType | char |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:7:7:7:7 | i | public | IntType | |
+| fields.cpp:3:8:3:12 | Entry | fields.cpp:7:7:7:7 | i | public | IntegralDumpType | |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:7:7:7:7 | i | public | MicrosoftInt32Type | |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:9:7:9:14 | internal | private | IntType | |
+| fields.cpp:3:8:3:12 | Entry | fields.cpp:9:7:9:14 | internal | private | IntegralDumpType | |
| fields.cpp:3:8:3:12 | Entry | fields.cpp:9:7:9:14 | internal | private | MicrosoftInt32Type | |
-| fields.cpp:12:7:12:10 | Name | fields.cpp:13:15:13:15 | s | private | PointerType | const char |
-| fields.cpp:16:7:16:11 | Table | fields.cpp:17:9:17:9 | p | private | PointerType | Name |
+| fields.cpp:12:7:12:10 | Name | fields.cpp:13:15:13:15 | s | private | PointerDumpType | const char |
+| fields.cpp:16:7:16:11 | Table | fields.cpp:17:9:17:9 | p | private | PointerDumpType | Name |
| fields.cpp:16:7:16:11 | Table | fields.cpp:18:7:18:8 | sz | private | IntType | |
+| fields.cpp:16:7:16:11 | Table | fields.cpp:18:7:18:8 | sz | private | IntegralDumpType | |
| fields.cpp:16:7:16:11 | Table | fields.cpp:18:7:18:8 | sz | private | MicrosoftInt32Type | |
| fields.cpp:26:7:26:10 | Date | fields.cpp:28:16:28:26 | cache_valid | private | BoolType | |
+| fields.cpp:26:7:26:10 | Date | fields.cpp:28:16:28:26 | cache_valid | private | IntegralDumpType | |
| fields.cpp:26:7:26:10 | Date | fields.cpp:30:17:30:21 | cache | public | CharPointerType | char |
+| fields.cpp:26:7:26:10 | Date | fields.cpp:30:17:30:21 | cache | public | PointerDumpType | char |
diff --git a/cpp/ql/test/library-tests/functions/routinetype/types.expected b/cpp/ql/test/library-tests/functions/routinetype/types.expected
index d620bea517e..ca70c1ac23a 100644
--- a/cpp/ql/test/library-tests/functions/routinetype/types.expected
+++ b/cpp/ql/test/library-tests/functions/routinetype/types.expected
@@ -1 +1 @@
-| routinetype.cpp:2:7:2:19 | myRoutineType | file://:0:0:0:0 | ..()(..) | RoutineType |
+| routinetype.cpp:2:7:2:19 | myRoutineType | file://:0:0:0:0 | ..()(..) | PrintableElement, RoutineDumpType |
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 295ad79b9e2..040dbe0bfb5 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -5925,7 +5925,7 @@ ir.cpp:
# 705| getStmt(0): [ReturnStmt] return ...
# 705| getExpr(): [ConditionalExpr] ... ? ... : ...
# 705| Type = [UnknownType] unknown
-# 705| ValueCategory = prvalue
+# 705| ValueCategory = prvalue(load)
# 705| getCondition(): [LTExpr] ... < ...
# 705| Type = [UnknownType] unknown
# 705| ValueCategory = prvalue
diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected
index 472ba0a1b7c..7478060a95b 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected
+++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected
@@ -592,6 +592,8 @@
| test.c:654:9:654:9 | i | -2147483648 |
| test.c:658:7:658:7 | u | 0 |
| test.c:659:9:659:9 | u | 0 |
+| test.c:664:12:664:12 | s | -2147483648 |
+| test.c:665:7:665:8 | s2 | -4 |
| test.cpp:10:7:10:7 | b | -2147483648 |
| test.cpp:11:5:11:5 | x | -2147483648 |
| test.cpp:13:10:13:10 | x | -2147483648 |
diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c
index 28c9f94d959..40168c3e697 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c
+++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c
@@ -659,3 +659,8 @@ void guard_bound_out_of_range(void) {
out(u); // unreachable [BUG: is 0 .. +max]
}
}
+
+void test_mod(int s) {
+ int s2 = s % 5;
+ out(s2); // -4 .. 4
+}
diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected
index 0ea6a6ca311..ce6bed728eb 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected
+++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected
@@ -592,6 +592,8 @@
| test.c:654:9:654:9 | i | 2147483647 |
| test.c:658:7:658:7 | u | 0 |
| test.c:659:9:659:9 | u | 4294967295 |
+| test.c:664:12:664:12 | s | 2147483647 |
+| test.c:665:7:665:8 | s2 | 4 |
| test.cpp:10:7:10:7 | b | 2147483647 |
| test.cpp:11:5:11:5 | x | 2147483647 |
| test.cpp:13:10:13:10 | x | 2147483647 |
diff --git a/cpp/ql/test/library-tests/typedefs/Typedefs2.expected b/cpp/ql/test/library-tests/typedefs/Typedefs2.expected
index 8645ce97fcd..75659f24bf3 100644
--- a/cpp/ql/test/library-tests/typedefs/Typedefs2.expected
+++ b/cpp/ql/test/library-tests/typedefs/Typedefs2.expected
@@ -1,2 +1,2 @@
-| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:8:15:8:18 | TYPE | CTypedefType, LocalTypedefType |
-| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:9:9:9:9 | D | DirectAccessHolder, LocalClass, MetricClass, StructLikeClass |
+| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:8:15:8:18 | TYPE | CTypedefType, LocalTypedefType, PrintableElement, UserDumpType |
+| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:9:9:9:9 | D | DirectAccessHolder, LocalClass, MetricClass, PrintableElement, StructLikeClass, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/__wchar_t/wchar_t.expected b/cpp/ql/test/library-tests/types/__wchar_t/wchar_t.expected
index 84106f07a92..de87cc30f58 100644
--- a/cpp/ql/test/library-tests/types/__wchar_t/wchar_t.expected
+++ b/cpp/ql/test/library-tests/types/__wchar_t/wchar_t.expected
@@ -1,3 +1,3 @@
-| file://:0:0:0:0 | __wchar_t * | PointerType | Wchar_t, WideCharType |
-| file://:0:0:0:0 | const __wchar_t | SpecifiedType | Wchar_t, WideCharType |
-| file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | |
+| file://:0:0:0:0 | __wchar_t * | PointerDumpType, PrintableElement | IntegralDumpType, PrintableElement, Wchar_t, WideCharType |
+| file://:0:0:0:0 | const __wchar_t | PrintableElement, SpecifiedDumpType | IntegralDumpType, PrintableElement, Wchar_t, WideCharType |
+| file://:0:0:0:0 | wchar_t | IntegralDumpType, PrintableElement, Wchar_t, WideCharType | |
diff --git a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fastestminimumwidth.expected b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fastestminimumwidth.expected
index 13fe25a4819..b2c9acd8c14 100644
--- a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fastestminimumwidth.expected
+++ b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fastestminimumwidth.expected
@@ -1,8 +1,8 @@
-| cstd_types.cpp:47:13:47:15 | if8 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast8_t |
-| cstd_types.cpp:48:14:48:17 | if16 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast16_t |
-| cstd_types.cpp:49:14:49:17 | if32 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast32_t |
-| cstd_types.cpp:50:14:50:17 | if64 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast64_t |
-| cstd_types.cpp:51:14:51:16 | uf8 | CTypedefType, FastestMinimumWidthIntegralType, UInt_fast8_t |
-| cstd_types.cpp:52:15:52:18 | uf16 | CTypedefType, FastestMinimumWidthIntegralType, UInt_fast16_t |
-| cstd_types.cpp:53:15:53:18 | uf32 | CTypedefType, FastestMinimumWidthIntegralType, UInt_fast32_t |
-| cstd_types.cpp:54:15:54:18 | uf64 | CTypedefType, FastestMinimumWidthIntegralType, UInt_fast64_t |
\ No newline at end of file
+| cstd_types.cpp:47:13:47:15 | if8 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast8_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:48:14:48:17 | if16 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast16_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:49:14:49:17 | if32 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast32_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:50:14:50:17 | if64 | CTypedefType, FastestMinimumWidthIntegralType, Int_fast64_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:51:14:51:16 | uf8 | CTypedefType, FastestMinimumWidthIntegralType, PrintableElement, UInt_fast8_t, UserDumpType |
+| cstd_types.cpp:52:15:52:18 | uf16 | CTypedefType, FastestMinimumWidthIntegralType, PrintableElement, UInt_fast16_t, UserDumpType |
+| cstd_types.cpp:53:15:53:18 | uf32 | CTypedefType, FastestMinimumWidthIntegralType, PrintableElement, UInt_fast32_t, UserDumpType |
+| cstd_types.cpp:54:15:54:18 | uf64 | CTypedefType, FastestMinimumWidthIntegralType, PrintableElement, UInt_fast64_t, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidth.expected b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidth.expected
index d1c64343636..bfa2a29f9f3 100644
--- a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidth.expected
+++ b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidth.expected
@@ -1,8 +1,8 @@
-| cstd_types.cpp:31:8:31:9 | i8 | CTypedefType, FixedWidthIntegralType, Int8_t |
-| cstd_types.cpp:32:9:32:11 | i16 | CTypedefType, FixedWidthIntegralType, Int16_t |
-| cstd_types.cpp:33:9:33:11 | i32 | CTypedefType, FixedWidthIntegralType, Int32_t |
-| cstd_types.cpp:34:9:34:11 | i64 | CTypedefType, FixedWidthIntegralType, Int64_t |
-| cstd_types.cpp:35:9:35:11 | ui8 | CTypedefType, FixedWidthIntegralType, UInt8_t |
-| cstd_types.cpp:36:10:36:13 | ui16 | CTypedefType, FixedWidthIntegralType, UInt16_t |
-| cstd_types.cpp:37:10:37:13 | ui32 | CTypedefType, FixedWidthIntegralType, UInt32_t |
-| cstd_types.cpp:38:10:38:13 | ui64 | CTypedefType, FixedWidthIntegralType, UInt64_t |
+| cstd_types.cpp:31:8:31:9 | i8 | CTypedefType, FixedWidthIntegralType, Int8_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:32:9:32:11 | i16 | CTypedefType, FixedWidthIntegralType, Int16_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:33:9:33:11 | i32 | CTypedefType, FixedWidthIntegralType, Int32_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:34:9:34:11 | i64 | CTypedefType, FixedWidthIntegralType, Int64_t, PrintableElement, UserDumpType |
+| cstd_types.cpp:35:9:35:11 | ui8 | CTypedefType, FixedWidthIntegralType, PrintableElement, UInt8_t, UserDumpType |
+| cstd_types.cpp:36:10:36:13 | ui16 | CTypedefType, FixedWidthIntegralType, PrintableElement, UInt16_t, UserDumpType |
+| cstd_types.cpp:37:10:37:13 | ui32 | CTypedefType, FixedWidthIntegralType, PrintableElement, UInt32_t, UserDumpType |
+| cstd_types.cpp:38:10:38:13 | ui64 | CTypedefType, FixedWidthIntegralType, PrintableElement, UInt64_t, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidthenum.expected b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidthenum.expected
index d9884b22b00..f313ab23b1a 100644
--- a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidthenum.expected
+++ b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_fixedwidthenum.expected
@@ -1,2 +1,2 @@
-| cstd_types.cpp:74:4:74:6 | _e0 | Enum, FixedWidthEnumType |
-| cstd_types.cpp:75:4:75:6 | _e1 | FixedWidthEnumType, ScopedEnum |
+| cstd_types.cpp:74:4:74:6 | _e0 | Enum, FixedWidthEnumType, PrintableElement, UserDumpType |
+| cstd_types.cpp:75:4:75:6 | _e1 | FixedWidthEnumType, PrintableElement, ScopedEnum, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_maximumwidth.expected b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_maximumwidth.expected
index 0bf7779fcaf..6b57f8be126 100644
--- a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_maximumwidth.expected
+++ b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_maximumwidth.expected
@@ -1,2 +1,2 @@
-| cstd_types.cpp:55:10:55:11 | im | CTypedefType, Intmax_t, MaximumWidthIntegralType |
-| cstd_types.cpp:56:11:56:13 | uim | CTypedefType, MaximumWidthIntegralType, Uintmax_t |
+| cstd_types.cpp:55:10:55:11 | im | CTypedefType, Intmax_t, MaximumWidthIntegralType, PrintableElement, UserDumpType |
+| cstd_types.cpp:56:11:56:13 | uim | CTypedefType, MaximumWidthIntegralType, PrintableElement, Uintmax_t, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_minimumwidth.expected b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_minimumwidth.expected
index 2984f07be8c..aac3507a366 100644
--- a/cpp/ql/test/library-tests/types/cstd_types/cstd_types_minimumwidth.expected
+++ b/cpp/ql/test/library-tests/types/cstd_types/cstd_types_minimumwidth.expected
@@ -1,8 +1,8 @@
-| cstd_types.cpp:39:15:39:16 | l8 | CTypedefType, Int_least8_t, MinimumWidthIntegralType |
-| cstd_types.cpp:40:15:40:17 | l16 | CTypedefType, Int_least16_t, MinimumWidthIntegralType |
-| cstd_types.cpp:41:15:41:17 | l32 | CTypedefType, Int_least32_t, MinimumWidthIntegralType |
-| cstd_types.cpp:42:15:42:17 | l64 | CTypedefType, Int_least64_t, MinimumWidthIntegralType |
-| cstd_types.cpp:43:15:43:17 | ul8 | CTypedefType, MinimumWidthIntegralType, UInt_least8_t |
-| cstd_types.cpp:44:16:44:19 | ul16 | CTypedefType, MinimumWidthIntegralType, UInt_least16_t |
-| cstd_types.cpp:45:16:45:19 | ul32 | CTypedefType, MinimumWidthIntegralType, UInt_least32_t |
-| cstd_types.cpp:46:16:46:19 | ul64 | CTypedefType, MinimumWidthIntegralType, UInt_least64_t |
+| cstd_types.cpp:39:15:39:16 | l8 | CTypedefType, Int_least8_t, MinimumWidthIntegralType, PrintableElement, UserDumpType |
+| cstd_types.cpp:40:15:40:17 | l16 | CTypedefType, Int_least16_t, MinimumWidthIntegralType, PrintableElement, UserDumpType |
+| cstd_types.cpp:41:15:41:17 | l32 | CTypedefType, Int_least32_t, MinimumWidthIntegralType, PrintableElement, UserDumpType |
+| cstd_types.cpp:42:15:42:17 | l64 | CTypedefType, Int_least64_t, MinimumWidthIntegralType, PrintableElement, UserDumpType |
+| cstd_types.cpp:43:15:43:17 | ul8 | CTypedefType, MinimumWidthIntegralType, PrintableElement, UInt_least8_t, UserDumpType |
+| cstd_types.cpp:44:16:44:19 | ul16 | CTypedefType, MinimumWidthIntegralType, PrintableElement, UInt_least16_t, UserDumpType |
+| cstd_types.cpp:45:16:45:19 | ul32 | CTypedefType, MinimumWidthIntegralType, PrintableElement, UInt_least32_t, UserDumpType |
+| cstd_types.cpp:46:16:46:19 | ul64 | CTypedefType, MinimumWidthIntegralType, PrintableElement, UInt_least64_t, UserDumpType |
diff --git a/cpp/ql/test/library-tests/types/integral_types_ms/vars.expected b/cpp/ql/test/library-tests/types/integral_types_ms/vars.expected
index d2aac7454fd..31a7f01ba5f 100644
--- a/cpp/ql/test/library-tests/types/integral_types_ms/vars.expected
+++ b/cpp/ql/test/library-tests/types/integral_types_ms/vars.expected
@@ -1,4 +1,4 @@
-| integral_types.cpp:2:8:2:9 | i8 | file://:0:0:0:0 | char | MicrosoftInt8Type, PlainCharType |
-| integral_types.cpp:3:9:3:11 | i16 | file://:0:0:0:0 | short | MicrosoftInt16Type, ShortType |
-| integral_types.cpp:4:9:4:11 | i32 | file://:0:0:0:0 | int | IntType, MicrosoftInt32Type |
-| integral_types.cpp:5:9:5:11 | i64 | file://:0:0:0:0 | long long | LongLongType, MicrosoftInt64Type |
+| integral_types.cpp:2:8:2:9 | i8 | file://:0:0:0:0 | char | IntegralDumpType, MicrosoftInt8Type, PlainCharType, PrintableElement |
+| integral_types.cpp:3:9:3:11 | i16 | file://:0:0:0:0 | short | IntegralDumpType, MicrosoftInt16Type, PrintableElement, ShortType |
+| integral_types.cpp:4:9:4:11 | i32 | file://:0:0:0:0 | int | IntType, IntegralDumpType, MicrosoftInt32Type, PrintableElement |
+| integral_types.cpp:5:9:5:11 | i64 | file://:0:0:0:0 | long long | IntegralDumpType, LongLongType, MicrosoftInt64Type, PrintableElement |
diff --git a/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected b/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected
index e0f36ebd68a..a7d80758611 100644
--- a/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected
+++ b/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected
@@ -1,3 +1,3 @@
-| file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | |
-| file://:0:0:0:0 | wchar_t * | PointerType | CTypedefType, Wchar_t |
-| ms.c:2:24:2:30 | wchar_t | CTypedefType, Wchar_t | |
+| file://:0:0:0:0 | wchar_t | IntegralDumpType, PrintableElement, Wchar_t, WideCharType | |
+| file://:0:0:0:0 | wchar_t * | PointerDumpType, PrintableElement | CTypedefType, PrintableElement, UserDumpType, Wchar_t |
+| ms.c:2:24:2:30 | wchar_t | CTypedefType, PrintableElement, UserDumpType, Wchar_t | |
diff --git a/cpp/ql/test/library-tests/variables/variables/types.expected b/cpp/ql/test/library-tests/variables/variables/types.expected
index 712ec74c914..a77e0ec43d8 100644
--- a/cpp/ql/test/library-tests/variables/variables/types.expected
+++ b/cpp/ql/test/library-tests/variables/variables/types.expected
@@ -1,94 +1,94 @@
-| ..()(..) | RoutineType | | | | |
-| ..(*)(..) | FunctionPointerType | | ..()(..) | | |
-| _Complex __float128 | BinaryFloatingPointType, ComplexNumberType | | | | |
-| _Complex double | BinaryFloatingPointType, ComplexNumberType | | | | |
-| _Complex float | BinaryFloatingPointType, ComplexNumberType | | | | |
-| _Complex long double | BinaryFloatingPointType, ComplexNumberType | | | | |
-| _Decimal32 | Decimal32Type | | | | |
-| _Decimal64 | Decimal64Type | | | | |
-| _Decimal128 | Decimal128Type | | | | |
-| _Float32 | BinaryFloatingPointType, RealNumberType | | | | |
-| _Float32x | BinaryFloatingPointType, RealNumberType | | | | |
-| _Float64 | BinaryFloatingPointType, RealNumberType | | | | |
-| _Float64x | BinaryFloatingPointType, RealNumberType | | | | |
-| _Float128 | BinaryFloatingPointType, RealNumberType | | | | |
-| _Float128x | BinaryFloatingPointType, RealNumberType | | | | |
-| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
-| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | |
-| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
-| __float128 | Float128Type | | | | |
-| __int128 | Int128Type | | | | |
-| __va_list_tag | DirectAccessHolder, MetricClass, Struct, StructLikeClass | | | | |
-| __va_list_tag & | LValueReferenceType | | __va_list_tag | | |
-| __va_list_tag && | RValueReferenceType | | __va_list_tag | | |
-| address | DirectAccessHolder, MetricClass, Struct, StructLikeClass | | | | |
-| address & | LValueReferenceType | | address | | |
-| address && | RValueReferenceType | | address | | |
-| auto | AutoType | | | | |
-| bool | BoolType | | | | |
-| char | MicrosoftInt8Type, PlainCharType | | | | |
-| char8_t | Char8Type | | | | |
-| char16_t | Char16Type | | | | |
-| char32_t | Char32Type | | | | |
-| char * | CharPointerType | | char | | |
-| char *[3] | ArrayType | char * | char * | | |
-| char *[32] | ArrayType | char * | char * | | |
-| char *[] | ArrayType | char * | char * | | |
-| char[2] | ArrayType | char | char | | |
-| char[3] | ArrayType | char | char | | |
-| char[5] | ArrayType | char | char | | |
-| char[6] | ArrayType | char | char | | |
-| char[8] | ArrayType | char | char | | |
-| char[9] | ArrayType | char | char | | |
-| char[10] | ArrayType | char | char | | |
-| char[53] | ArrayType | char | char | | |
-| char[] | ArrayType | char | char | | |
-| const __va_list_tag | SpecifiedType | | __va_list_tag | | |
-| const __va_list_tag & | LValueReferenceType | | const __va_list_tag | | |
-| const address | SpecifiedType | | address | | |
-| const address & | LValueReferenceType | | const address | | |
-| const char | SpecifiedType | | char | | |
-| const char * | PointerType | | const char | | |
-| const char *[3] | ArrayType | const char * | const char * | | |
-| const char *[] | ArrayType | const char * | const char * | | |
-| const char[5] | ArrayType | const char | const char | | |
-| const char[6] | ArrayType | const char | const char | | |
-| const char[8] | ArrayType | const char | const char | | |
-| const char[9] | ArrayType | const char | const char | | |
-| const char[10] | ArrayType | const char | const char | | |
-| const char[53] | ArrayType | const char | const char | | |
-| const double | SpecifiedType | | double | | |
-| const int | SpecifiedType | | int | | |
-| decltype(nullptr) | NullPointerType | | | | |
-| double | DoubleType | | | | |
-| error | ErroneousType | | | | |
-| float | FloatType | | | | |
-| float[3] | ArrayType | float | float | | |
-| int | IntType, MicrosoftInt32Type | | | | |
-| int * | IntPointerType | | int | | |
-| int[4] | ArrayType | int | int | | |
-| int[8] | ArrayType | int | int | | |
-| int[10] | ArrayType | int | int | | |
-| int[10][20] | ArrayType | int[20] | int[20] | | |
-| int[20] | ArrayType | int | int | | |
-| int[] | ArrayType | int | int | | |
-| long | LongType | | | | |
-| long double | LongDoubleType | | | | |
-| long long | LongLongType, MicrosoftInt64Type | | | | |
-| short | MicrosoftInt16Type, ShortType | | | | |
-| signed __int128 | Int128Type | | | | |
-| signed char | SignedCharType | | | | |
-| signed int | IntType | | | | |
-| signed long | LongType | | | | |
-| signed long long | LongLongType | | | | |
-| signed short | ShortType | | | | |
-| unknown | UnknownType | | | | |
-| unsigned __int128 | Int128Type | | | | unsigned integral |
-| unsigned char | UnsignedCharType | | | | unsigned integral |
-| unsigned int | IntType | | | unsigned int | unsigned integral |
-| unsigned long | LongType | | | | unsigned integral |
-| unsigned long long | LongLongType | | | | unsigned integral |
-| unsigned short | ShortType | | | | unsigned integral |
-| void | VoidType | | | | |
-| void * | VoidPointerType | | void | | |
-| wchar_t | Wchar_t, WideCharType | | | | |
+| ..()(..) | PrintableElement, RoutineDumpType | | | | |
+| ..(*)(..) | FunctionPointerDumpType, PrintableElement | | ..()(..) | | |
+| _Complex __float128 | BinaryFloatingPointType, BuiltInDumpType, ComplexNumberType, PrintableElement | | | | |
+| _Complex double | BinaryFloatingPointType, BuiltInDumpType, ComplexNumberType, PrintableElement | | | | |
+| _Complex float | BinaryFloatingPointType, BuiltInDumpType, ComplexNumberType, PrintableElement | | | | |
+| _Complex long double | BinaryFloatingPointType, BuiltInDumpType, ComplexNumberType, PrintableElement | | | | |
+| _Decimal32 | BuiltInDumpType, Decimal32Type, PrintableElement | | | | |
+| _Decimal64 | BuiltInDumpType, Decimal64Type, PrintableElement | | | | |
+| _Decimal128 | BuiltInDumpType, Decimal128Type, PrintableElement | | | | |
+| _Float32 | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Float32x | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Float64 | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Float64x | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Float128 | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Float128x | BinaryFloatingPointType, BuiltInDumpType, PrintableElement, RealNumberType | | | | |
+| _Imaginary double | BinaryFloatingPointType, BuiltInDumpType, ImaginaryNumberType, PrintableElement | | | | |
+| _Imaginary float | BinaryFloatingPointType, BuiltInDumpType, ImaginaryNumberType, PrintableElement | | | | |
+| _Imaginary long double | BinaryFloatingPointType, BuiltInDumpType, ImaginaryNumberType, PrintableElement | | | | |
+| __float128 | BuiltInDumpType, Float128Type, PrintableElement | | | | |
+| __int128 | Int128Type, IntegralDumpType, PrintableElement | | | | |
+| __va_list_tag | DirectAccessHolder, MetricClass, PrintableElement, Struct, StructLikeClass, UserDumpType | | | | |
+| __va_list_tag & | LValueReferenceDumpType, PrintableElement | | __va_list_tag | | |
+| __va_list_tag && | PrintableElement, RValueReferenceDumpType | | __va_list_tag | | |
+| address | DirectAccessHolder, MetricClass, PrintableElement, Struct, StructLikeClass, UserDumpType | | | | |
+| address & | LValueReferenceDumpType, PrintableElement | | address | | |
+| address && | PrintableElement, RValueReferenceDumpType | | address | | |
+| auto | AutoType, PrintableElement, UserDumpType | | | | |
+| bool | BoolType, IntegralDumpType, PrintableElement | | | | |
+| char | IntegralDumpType, MicrosoftInt8Type, PlainCharType, PrintableElement | | | | |
+| char8_t | Char8Type, IntegralDumpType, PrintableElement | | | | |
+| char16_t | Char16Type, IntegralDumpType, PrintableElement | | | | |
+| char32_t | Char32Type, IntegralDumpType, PrintableElement | | | | |
+| char * | CharPointerType, PointerDumpType, PrintableElement | | char | | |
+| char *[3] | ArrayDumpType, PrintableElement | char * | char * | | |
+| char *[32] | ArrayDumpType, PrintableElement | char * | char * | | |
+| char *[] | ArrayDumpType, PrintableElement | char * | char * | | |
+| char[2] | ArrayDumpType, PrintableElement | char | char | | |
+| char[3] | ArrayDumpType, PrintableElement | char | char | | |
+| char[5] | ArrayDumpType, PrintableElement | char | char | | |
+| char[6] | ArrayDumpType, PrintableElement | char | char | | |
+| char[8] | ArrayDumpType, PrintableElement | char | char | | |
+| char[9] | ArrayDumpType, PrintableElement | char | char | | |
+| char[10] | ArrayDumpType, PrintableElement | char | char | | |
+| char[53] | ArrayDumpType, PrintableElement | char | char | | |
+| char[] | ArrayDumpType, PrintableElement | char | char | | |
+| const __va_list_tag | PrintableElement, SpecifiedDumpType | | __va_list_tag | | |
+| const __va_list_tag & | LValueReferenceDumpType, PrintableElement | | const __va_list_tag | | |
+| const address | PrintableElement, SpecifiedDumpType | | address | | |
+| const address & | LValueReferenceDumpType, PrintableElement | | const address | | |
+| const char | PrintableElement, SpecifiedDumpType | | char | | |
+| const char * | PointerDumpType, PrintableElement | | const char | | |
+| const char *[3] | ArrayDumpType, PrintableElement | const char * | const char * | | |
+| const char *[] | ArrayDumpType, PrintableElement | const char * | const char * | | |
+| const char[5] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const char[6] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const char[8] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const char[9] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const char[10] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const char[53] | ArrayDumpType, PrintableElement | const char | const char | | |
+| const double | PrintableElement, SpecifiedDumpType | | double | | |
+| const int | PrintableElement, SpecifiedDumpType | | int | | |
+| decltype(nullptr) | BuiltInDumpType, NullPointerType, PrintableElement | | | | |
+| double | BuiltInDumpType, DoubleType, PrintableElement | | | | |
+| error | BuiltInDumpType, ErroneousType, PrintableElement | | | | |
+| float | BuiltInDumpType, FloatType, PrintableElement | | | | |
+| float[3] | ArrayDumpType, PrintableElement | float | float | | |
+| int | IntType, IntegralDumpType, MicrosoftInt32Type, PrintableElement | | | | |
+| int * | IntPointerType, PointerDumpType, PrintableElement | | int | | |
+| int[4] | ArrayDumpType, PrintableElement | int | int | | |
+| int[8] | ArrayDumpType, PrintableElement | int | int | | |
+| int[10] | ArrayDumpType, PrintableElement | int | int | | |
+| int[10][20] | ArrayDumpType, PrintableElement | int[20] | int[20] | | |
+| int[20] | ArrayDumpType, PrintableElement | int | int | | |
+| int[] | ArrayDumpType, PrintableElement | int | int | | |
+| long | IntegralDumpType, LongType, PrintableElement | | | | |
+| long double | BuiltInDumpType, LongDoubleType, PrintableElement | | | | |
+| long long | IntegralDumpType, LongLongType, MicrosoftInt64Type, PrintableElement | | | | |
+| short | IntegralDumpType, MicrosoftInt16Type, PrintableElement, ShortType | | | | |
+| signed __int128 | Int128Type, IntegralDumpType, PrintableElement | | | | |
+| signed char | IntegralDumpType, PrintableElement, SignedCharType | | | | |
+| signed int | IntType, IntegralDumpType, PrintableElement | | | | |
+| signed long | IntegralDumpType, LongType, PrintableElement | | | | |
+| signed long long | IntegralDumpType, LongLongType, PrintableElement | | | | |
+| signed short | IntegralDumpType, PrintableElement, ShortType | | | | |
+| unknown | BuiltInDumpType, PrintableElement, UnknownType | | | | |
+| unsigned __int128 | Int128Type, IntegralDumpType, PrintableElement | | | | unsigned integral |
+| unsigned char | IntegralDumpType, PrintableElement, UnsignedCharType | | | | unsigned integral |
+| unsigned int | IntType, IntegralDumpType, PrintableElement | | | unsigned int | unsigned integral |
+| unsigned long | IntegralDumpType, LongType, PrintableElement | | | | unsigned integral |
+| unsigned long long | IntegralDumpType, LongLongType, PrintableElement | | | | unsigned integral |
+| unsigned short | IntegralDumpType, PrintableElement, ShortType | | | | unsigned integral |
+| void | BuiltInDumpType, PrintableElement, VoidType | | | | |
+| void * | PointerDumpType, PrintableElement, VoidPointerType | | void | | |
+| wchar_t | IntegralDumpType, PrintableElement, Wchar_t, WideCharType | | | | |
diff --git a/cpp/ql/test/library-tests/variables/variables/variable.expected b/cpp/ql/test/library-tests/variables/variables/variable.expected
index e99ff83d440..ad190643839 100644
--- a/cpp/ql/test/library-tests/variables/variables/variable.expected
+++ b/cpp/ql/test/library-tests/variables/variables/variable.expected
@@ -1,70 +1,111 @@
+| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | __va_list_tag && | DumpVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | __va_list_tag && | SemanticStackVariable | | |
+| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | address && | DumpVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | address && | SemanticStackVariable | | |
+| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const __va_list_tag & | DumpVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const __va_list_tag & | SemanticStackVariable | | |
+| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const address & | DumpVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const address & | SemanticStackVariable | | |
+| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | unsigned int | DumpVariable | | |
| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | unsigned int | Field | | |
+| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | DumpVariable | | |
| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | Field | | |
+| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | DumpVariable | | |
| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | Field | | |
+| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | DumpVariable | | |
| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | Field | | |
+| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | DumpVariable | | |
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
+| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | DumpVariable | | |
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
+| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | DumpVariable | | |
| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
+| variables.cpp:5:11:5:11 | c | file://:0:0:0:0 | const int | DumpVariable | const | static |
| variables.cpp:5:11:5:11 | c | file://:0:0:0:0 | const int | GlobalVariable | const | static |
| variables.cpp:5:11:5:11 | c | file://:0:0:0:0 | const int | StaticStorageDurationVariable | const | static |
+| variables.cpp:6:14:6:15 | pi | file://:0:0:0:0 | const double | DumpVariable | const | static |
| variables.cpp:6:14:6:15 | pi | file://:0:0:0:0 | const double | GlobalVariable | const | static |
| variables.cpp:6:14:6:15 | pi | file://:0:0:0:0 | const double | StaticStorageDurationVariable | const | static |
+| variables.cpp:8:10:8:10 | a | file://:0:0:0:0 | unsigned int | DumpVariable | | |
| variables.cpp:8:10:8:10 | a | file://:0:0:0:0 | unsigned int | GlobalVariable | | |
| variables.cpp:8:10:8:10 | a | file://:0:0:0:0 | unsigned int | StaticStorageDurationVariable | | |
+| variables.cpp:10:14:10:14 | b | file://:0:0:0:0 | unsigned int | DumpVariable | | |
| variables.cpp:10:14:10:14 | b | file://:0:0:0:0 | unsigned int | GlobalVariable | | |
| variables.cpp:10:14:10:14 | b | file://:0:0:0:0 | unsigned int | StaticStorageDurationVariable | | |
+| variables.cpp:12:13:12:17 | kings | file://:0:0:0:0 | const char *[] | DumpVariable | | |
| variables.cpp:12:13:12:17 | kings | file://:0:0:0:0 | const char *[] | GlobalVariable | | |
| variables.cpp:12:13:12:17 | kings | file://:0:0:0:0 | const char *[] | StaticStorageDurationVariable | | |
+| variables.cpp:14:6:14:6 | p | file://:0:0:0:0 | int * | DumpVariable | | |
| variables.cpp:14:6:14:6 | p | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:14:6:14:6 | p | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
+| variables.cpp:14:9:14:9 | q | file://:0:0:0:0 | int | DumpVariable | | |
| variables.cpp:14:9:14:9 | q | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:14:9:14:9 | q | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
+| variables.cpp:15:12:15:13 | v1 | file://:0:0:0:0 | int[10] | DumpVariable | | static |
| variables.cpp:15:12:15:13 | v1 | file://:0:0:0:0 | int[10] | GlobalVariable | | static |
| variables.cpp:15:12:15:13 | v1 | file://:0:0:0:0 | int[10] | StaticStorageDurationVariable | | static |
+| variables.cpp:15:21:15:22 | pv | file://:0:0:0:0 | int * | DumpVariable | | static |
| variables.cpp:15:21:15:22 | pv | file://:0:0:0:0 | int * | GlobalVariable | | static |
| variables.cpp:15:21:15:22 | pv | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | static |
+| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | DumpVariable | | |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | FunctionPointerVariable | | |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | GlobalVariable | | |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | StaticStorageDurationVariable | | |
+| variables.cpp:19:7:19:8 | v2 | file://:0:0:0:0 | float[3] | DumpVariable | | |
| variables.cpp:19:7:19:8 | v2 | file://:0:0:0:0 | float[3] | GlobalVariable | | |
| variables.cpp:19:7:19:8 | v2 | file://:0:0:0:0 | float[3] | StaticStorageDurationVariable | | |
+| variables.cpp:20:7:20:8 | v3 | file://:0:0:0:0 | char *[32] | DumpVariable | | |
| variables.cpp:20:7:20:8 | v3 | file://:0:0:0:0 | char *[32] | GlobalVariable | | |
| variables.cpp:20:7:20:8 | v3 | file://:0:0:0:0 | char *[32] | StaticStorageDurationVariable | | |
+| variables.cpp:22:5:22:6 | d2 | file://:0:0:0:0 | int[10][20] | DumpVariable | | |
| variables.cpp:22:5:22:6 | d2 | file://:0:0:0:0 | int[10][20] | GlobalVariable | | |
| variables.cpp:22:5:22:6 | d2 | file://:0:0:0:0 | int[10][20] | StaticStorageDurationVariable | | |
+| variables.cpp:24:6:24:7 | v4 | file://:0:0:0:0 | char[3] | DumpVariable | | |
| variables.cpp:24:6:24:7 | v4 | file://:0:0:0:0 | char[3] | GlobalVariable | | |
| variables.cpp:24:6:24:7 | v4 | file://:0:0:0:0 | char[3] | StaticStorageDurationVariable | | |
+| variables.cpp:26:5:26:6 | v5 | file://:0:0:0:0 | int[8] | DumpVariable | | |
| variables.cpp:26:5:26:6 | v5 | file://:0:0:0:0 | int[8] | GlobalVariable | | |
| variables.cpp:26:5:26:6 | v5 | file://:0:0:0:0 | int[8] | StaticStorageDurationVariable | | |
+| variables.cpp:28:7:28:8 | p2 | file://:0:0:0:0 | char * | DumpVariable | | |
| variables.cpp:28:7:28:8 | p2 | file://:0:0:0:0 | char * | GlobalVariable | | |
| variables.cpp:28:7:28:8 | p2 | file://:0:0:0:0 | char * | StaticStorageDurationVariable | | |
+| variables.cpp:29:6:29:7 | p3 | file://:0:0:0:0 | char[] | DumpVariable | | |
| variables.cpp:29:6:29:7 | p3 | file://:0:0:0:0 | char[] | GlobalVariable | | |
| variables.cpp:29:6:29:7 | p3 | file://:0:0:0:0 | char[] | StaticStorageDurationVariable | | |
+| variables.cpp:31:6:31:10 | alpha | file://:0:0:0:0 | char[] | DumpVariable | | |
| variables.cpp:31:6:31:10 | alpha | file://:0:0:0:0 | char[] | GlobalVariable | | |
| variables.cpp:31:6:31:10 | alpha | file://:0:0:0:0 | char[] | StaticStorageDurationVariable | | |
+| variables.cpp:34:5:34:6 | av | file://:0:0:0:0 | int[] | DumpVariable | | |
| variables.cpp:34:5:34:6 | av | file://:0:0:0:0 | int[] | GlobalVariable | | |
| variables.cpp:34:5:34:6 | av | file://:0:0:0:0 | int[] | StaticStorageDurationVariable | | |
+| variables.cpp:35:6:35:8 | ap1 | file://:0:0:0:0 | int * | DumpVariable | | |
| variables.cpp:35:6:35:8 | ap1 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:35:6:35:8 | ap1 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
+| variables.cpp:36:6:36:8 | ap2 | file://:0:0:0:0 | int * | DumpVariable | | |
| variables.cpp:36:6:36:8 | ap2 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:36:6:36:8 | ap2 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
+| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | DumpVariable | | |
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
+| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | DumpVariable | | |
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable | | |
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | SemanticStackVariable | | |
+| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | DumpVariable | | static |
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | StaticLocalVariable | | static |
+| variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | DumpVariable | | |
| variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | Field | | |
+| variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | DumpVariable | | |
| variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | Field | | |
+| variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | DumpVariable | | |
| variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | Field | | |
+| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | DumpVariable | | |
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
+| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | DumpVariable | | static |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable | | static |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | StaticStorageDurationVariable | | static |
+| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | DumpVariable | | |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
index 41f7c968393..9113078062f 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
@@ -3,12 +3,8 @@
| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
-| tests.cpp:27:17:27:24 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
-| tests.cpp:29:17:29:23 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *' |
-| tests.cpp:34:36:34:43 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
-| tests.cpp:37:36:37:42 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
| tests.cpp:42:37:42:44 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
| tests.cpp:43:37:43:44 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/tests.cpp b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/tests.cpp
index cd802e2b501..5762ded379d 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/tests.cpp
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/tests.cpp
@@ -24,17 +24,17 @@ void tests() {
wprintf(L"%s", "Hello"); // GOOD
wprintf(L"%s", u"Hello"); // BAD: expecting char
- wprintf(L"%s", L"Hello"); // BAD: expecting char
+ wprintf(L"%s", L"Hello"); // BAD: expecting char [NOT DETECTED; correct on Microsoft platforms]
- wprintf(L"%S", "Hello"); // BAD: expecting wchar_t
+ wprintf(L"%S", "Hello"); // BAD: expecting wchar_t [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", u"Hello"); // BAD: expecting wchar_t
wprintf(L"%S", L"Hello"); // GOOD
swprintf(buffer, BUF_SIZE, u"%s", "Hello"); // GOOD
- swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // BAD: expecting char
+ swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // BAD: expecting char [NOT DETECTED; correct on Microsoft platforms]
swprintf(buffer, BUF_SIZE, u"%s", L"Hello"); // BAD: expecting char
- swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // BAD: expecting char16_t
+ swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // BAD: expecting char16_t [NOT DETECTED; correct on Microsoft platforms]
swprintf(buffer, BUF_SIZE, u"%S", u"Hello"); // GOOD
swprintf(buffer, BUF_SIZE, u"%S", L"Hello"); // BAD: expecting char16_t
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
index dbbf2c125bc..6b772112fe8 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
@@ -1,3 +1,2 @@
-| printf.cpp:31:31:31:37 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
| printf.cpp:43:29:43:35 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
| printf.cpp:50:29:50:35 | test | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/printf.cpp b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/printf.cpp
index deb022d3b12..596e7ac73fc 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/printf.cpp
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/printf.cpp
@@ -28,7 +28,7 @@ int sprintf(char *dest, char *format, ...);
void test1() {
WCHAR string[20];
- swprintf(string, u"test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string
+ swprintf(string, u"test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string [NOT DETECTED; correct on Microsoft platforms]
}
void test2() {
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
index f3feb82e695..b07994267cc 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
@@ -11,8 +11,6 @@
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int' |
-| printf1.h:154:18:154:19 | wc | This argument should be of type 'char *' but is of type 'wchar_t *' |
-| printf1.h:155:18:155:18 | c | This argument should be of type 'wchar_t *' but is of type 'char *' |
| printf1.h:168:19:168:19 | i | This argument should be of type 'long long' but is of type 'int' |
| printf1.h:169:19:169:20 | ui | This argument should be of type 'unsigned long long' but is of type 'unsigned int' |
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h
index f919c62a6bc..60ee2c8caad 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h
@@ -151,8 +151,8 @@ void test_chars(char c, wchar_t wc, wint_t wt)
void test_ws(char *c, wchar_t *wc)
{
wprintf(L"%s", c); // GOOD
- wprintf(L"%s", wc); // BAD
- wprintf(L"%S", c); // BAD
+ wprintf(L"%s", wc); // BAD [NOT DETECTED; correct on Microsoft platforms]
+ wprintf(L"%S", c); // BAD [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", wc); // GOOD
}
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
index df9773eda7d..315893913df 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
@@ -19,8 +19,6 @@
| printf1.h:116:16:116:24 | myString3 | This argument should be of type '__wchar_t *' but is of type 'int *' |
| printf1.h:117:16:117:24 | myString4 | This argument should be of type '__wchar_t *' but is of type 'int *' |
| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int' |
-| printf1.h:153:18:153:18 | c | This argument should be of type '__wchar_t *' but is of type 'char *' |
-| printf1.h:156:18:156:19 | wc | This argument should be of type 'char *' but is of type '__wchar_t *' |
| printf1.h:181:21:181:22 | ll | This argument should be of type 'int' but is of type 'long long' |
| printf1.h:182:21:182:23 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:185:21:185:23 | i64 | This argument should be of type 'int' but is of type 'long long' |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h
index 962dc44b1ca..e2d4f50fc1f 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h
@@ -150,10 +150,10 @@ void test_chars(char c, wchar_t wc, wint_t wt)
void test_ws(char *c, wchar_t *wc, wint_t *wt)
{
- wprintf(L"%s", c); // BAD
+ wprintf(L"%s", c); // BAD [NOT DETECTED; correct on non-Microsoft platforms]
wprintf(L"%s", wc); // GOOD
wprintf(L"%S", c); // GOOD
- wprintf(L"%S", wc); // BAD
+ wprintf(L"%S", wc); // BAD [NOT DETECTED; correct on non-Microsoft platforms]
}
void fun4()
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
index 752e9165c07..694f46e1d26 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
@@ -59,20 +59,20 @@ edges
| test.cpp:237:24:237:37 | (const char *)... | test.cpp:247:2:247:8 | local_size |
| test.cpp:245:2:245:9 | local_size | test.cpp:224:23:224:23 | s |
| test.cpp:247:2:247:8 | local_size | test.cpp:230:21:230:21 | s |
-| test.cpp:251:2:251:32 | Chi [array content] | test.cpp:289:17:289:20 | get_size output argument [array content] |
-| test.cpp:251:2:251:32 | Chi [array content] | test.cpp:305:18:305:21 | get_size output argument [array content] |
-| test.cpp:251:18:251:23 | call to getenv | test.cpp:251:2:251:32 | Chi [array content] |
-| test.cpp:251:18:251:31 | (const char *)... | test.cpp:251:2:251:32 | Chi [array content] |
+| test.cpp:251:2:251:32 | Chi [[]] | test.cpp:289:17:289:20 | get_size output argument [[]] |
+| test.cpp:251:2:251:32 | Chi [[]] | test.cpp:305:18:305:21 | get_size output argument [[]] |
+| test.cpp:251:18:251:23 | call to getenv | test.cpp:251:2:251:32 | Chi [[]] |
+| test.cpp:251:18:251:31 | (const char *)... | test.cpp:251:2:251:32 | Chi [[]] |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | (const char *)... | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | (const char *)... | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:289:17:289:20 | Chi | test.cpp:291:11:291:28 | ... * ... |
| test.cpp:289:17:289:20 | Chi | test.cpp:291:11:291:28 | ... * ... |
-| test.cpp:289:17:289:20 | get_size output argument [array content] | test.cpp:289:17:289:20 | Chi |
+| test.cpp:289:17:289:20 | get_size output argument [[]] | test.cpp:289:17:289:20 | Chi |
| test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... |
| test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... |
-| test.cpp:305:18:305:21 | get_size output argument [array content] | test.cpp:305:18:305:21 | Chi |
+| test.cpp:305:18:305:21 | get_size output argument [[]] | test.cpp:305:18:305:21 | Chi |
nodes
| test.cpp:40:21:40:24 | argv | semmle.label | argv |
| test.cpp:40:21:40:24 | argv | semmle.label | argv |
@@ -136,7 +136,7 @@ nodes
| test.cpp:241:9:241:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
| test.cpp:245:2:245:9 | local_size | semmle.label | local_size |
| test.cpp:247:2:247:8 | local_size | semmle.label | local_size |
-| test.cpp:251:2:251:32 | Chi [array content] | semmle.label | Chi [array content] |
+| test.cpp:251:2:251:32 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:251:2:251:32 | ChiPartial | semmle.label | ChiPartial |
| test.cpp:251:18:251:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:31 | (const char *)... | semmle.label | (const char *)... |
@@ -146,12 +146,12 @@ nodes
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:289:17:289:20 | Chi | semmle.label | Chi |
-| test.cpp:289:17:289:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] |
+| test.cpp:289:17:289:20 | get_size output argument [[]] | semmle.label | get_size output argument [[]] |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:18:305:21 | Chi | semmle.label | Chi |
-| test.cpp:305:18:305:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] |
+| test.cpp:305:18:305:21 | get_size output argument [[]] | semmle.label | get_size output argument [[]] |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected
index bdf00e0a5df..e2fefe4a442 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected
@@ -1,9 +1,68 @@
-| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
-| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
-| test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
-| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
-| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
-| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
-| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
-| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
-| test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
+edges
+| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
+| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
+| test2.cpp:25:22:25:23 | & ... | test2.cpp:27:2:27:11 | v |
+| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:2:27:11 | v |
+| test2.cpp:27:2:27:11 | v | test2.cpp:12:21:12:21 | v |
+| test5.cpp:9:7:9:9 | buf | test5.cpp:10:9:10:27 | Store |
+| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:10:9:10:27 | Store |
+| test5.cpp:10:9:10:27 | Store | test5.cpp:17:6:17:18 | call to getTaintedInt |
+| test5.cpp:10:9:10:27 | Store | test5.cpp:17:6:17:18 | call to getTaintedInt |
+| test5.cpp:10:9:10:27 | Store | test5.cpp:18:6:18:18 | call to getTaintedInt |
+| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
+| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
+| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
+| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
+| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
+| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
+| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
+| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
+| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
+| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
+| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
+| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
+| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
+| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
+nodes
+| test2.cpp:12:21:12:21 | v | semmle.label | v |
+| test2.cpp:14:11:14:11 | v | semmle.label | v |
+| test2.cpp:14:11:14:11 | v | semmle.label | v |
+| test2.cpp:14:11:14:11 | v | semmle.label | v |
+| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
+| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
+| test2.cpp:27:2:27:11 | v | semmle.label | v |
+| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
+| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
+| test5.cpp:10:9:10:27 | Store | semmle.label | Store |
+| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
+| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
+| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
+| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
+| test5.cpp:19:6:19:6 | y | semmle.label | y |
+| test5.cpp:19:6:19:6 | y | semmle.label | y |
+| test5.cpp:19:6:19:6 | y | semmle.label | y |
+| test.c:11:29:11:32 | argv | semmle.label | argv |
+| test.c:11:29:11:32 | argv | semmle.label | argv |
+| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
+| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
+| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
+| test.c:41:17:41:20 | argv | semmle.label | argv |
+| test.c:41:17:41:20 | argv | semmle.label | argv |
+| test.c:44:7:44:10 | len2 | semmle.label | len2 |
+| test.c:44:7:44:10 | len2 | semmle.label | len2 |
+| test.c:44:7:44:10 | len2 | semmle.label | len2 |
+| test.c:51:17:51:20 | argv | semmle.label | argv |
+| test.c:51:17:51:20 | argv | semmle.label | argv |
+| test.c:54:7:54:10 | len3 | semmle.label | len3 |
+| test.c:54:7:54:10 | len3 | semmle.label | len3 |
+| test.c:54:7:54:10 | len3 | semmle.label | len3 |
+#select
+| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
+| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
+| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | buf | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
+| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
+| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
+| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
+| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
+| test.c:44:7:44:10 | len2 | test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
+| test.c:54:7:54:10 | len3 | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected
index 097efb73b9f..5f3ed277912 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected
@@ -1,97 +1,60 @@
edges
| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
-| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
-| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
-| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
-| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
-| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
-| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
-| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
-| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
-| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
-| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
-| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
-| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
-| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
-| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
-| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
-| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
+| test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r |
+| test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r |
+| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r |
+| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r |
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
| test.cpp:8:9:8:12 | Store | test.cpp:24:11:24:18 | call to get_rand |
| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store |
-| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store |
-| test.cpp:13:2:13:15 | Chi [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] |
-| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] |
-| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] |
-| test.cpp:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] |
-| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] |
-| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] |
-| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r |
+| test.cpp:13:2:13:15 | Chi [[]] | test.cpp:30:13:30:14 | get_rand2 output argument [[]] |
+| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [[]] |
+| test.cpp:18:2:18:14 | Chi [[]] | test.cpp:36:13:36:13 | get_rand3 output argument [[]] |
+| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [[]] |
| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r |
| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r |
-| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r |
-| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | Chi |
+| test.cpp:30:13:30:14 | get_rand2 output argument [[]] | test.cpp:30:13:30:14 | Chi |
| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r |
-| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r |
-| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | Chi |
+| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | test.cpp:36:13:36:13 | Chi |
nodes
| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
-| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
-| test.c:21:17:21:17 | r | semmle.label | r |
-| test.c:21:17:21:17 | r | semmle.label | r |
| test.c:21:17:21:17 | r | semmle.label | r |
| test.c:34:13:34:18 | call to rand | semmle.label | call to rand |
-| test.c:34:13:34:18 | call to rand | semmle.label | call to rand |
-| test.c:35:5:35:5 | r | semmle.label | r |
-| test.c:35:5:35:5 | r | semmle.label | r |
| test.c:35:5:35:5 | r | semmle.label | r |
| test.c:44:13:44:16 | call to rand | semmle.label | call to rand |
-| test.c:44:13:44:16 | call to rand | semmle.label | call to rand |
| test.c:45:5:45:5 | r | semmle.label | r |
-| test.c:45:5:45:5 | r | semmle.label | r |
-| test.c:45:5:45:5 | r | semmle.label | r |
-| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... |
-| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... |
-| test.c:77:9:77:9 | r | semmle.label | r |
-| test.c:77:9:77:9 | r | semmle.label | r |
+| test.c:75:13:75:19 | call to rand | semmle.label | call to rand |
+| test.c:75:13:75:19 | call to rand | semmle.label | call to rand |
| test.c:77:9:77:9 | r | semmle.label | r |
+| test.c:81:14:81:17 | call to rand | semmle.label | call to rand |
+| test.c:81:23:81:26 | call to rand | semmle.label | call to rand |
+| test.c:83:9:83:9 | r | semmle.label | r |
| test.c:99:14:99:19 | call to rand | semmle.label | call to rand |
-| test.c:99:14:99:19 | call to rand | semmle.label | call to rand |
-| test.c:100:5:100:5 | r | semmle.label | r |
-| test.c:100:5:100:5 | r | semmle.label | r |
| test.c:100:5:100:5 | r | semmle.label | r |
| test.cpp:8:9:8:12 | Store | semmle.label | Store |
| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
-| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
-| test.cpp:13:2:13:15 | Chi [array content] | semmle.label | Chi [array content] |
-| test.cpp:13:2:13:15 | ChiPartial | semmle.label | ChiPartial |
+| test.cpp:13:2:13:15 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand |
-| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand |
-| test.cpp:18:2:18:14 | Chi [array content] | semmle.label | Chi [array content] |
-| test.cpp:18:2:18:14 | ChiPartial | semmle.label | ChiPartial |
-| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand |
+| test.cpp:18:2:18:14 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand |
| test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand |
| test.cpp:25:7:25:7 | r | semmle.label | r |
-| test.cpp:25:7:25:7 | r | semmle.label | r |
-| test.cpp:25:7:25:7 | r | semmle.label | r |
| test.cpp:30:13:30:14 | Chi | semmle.label | Chi |
-| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | semmle.label | get_rand2 output argument [array content] |
-| test.cpp:31:7:31:7 | r | semmle.label | r |
-| test.cpp:31:7:31:7 | r | semmle.label | r |
+| test.cpp:30:13:30:14 | get_rand2 output argument [[]] | semmle.label | get_rand2 output argument [[]] |
| test.cpp:31:7:31:7 | r | semmle.label | r |
| test.cpp:36:13:36:13 | Chi | semmle.label | Chi |
-| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | semmle.label | get_rand3 output argument [array content] |
-| test.cpp:37:7:37:7 | r | semmle.label | r |
-| test.cpp:37:7:37:7 | r | semmle.label | r |
+| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | semmle.label | get_rand3 output argument [[]] |
| test.cpp:37:7:37:7 | r | semmle.label | r |
#select
| test.c:21:17:21:17 | r | test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value |
| test.c:35:5:35:5 | r | test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:34:13:34:18 | call to rand | Uncontrolled value |
| test.c:45:5:45:5 | r | test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:44:13:44:16 | call to rand | Uncontrolled value |
-| test.c:77:9:77:9 | r | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value |
+| test.c:77:9:77:9 | r | test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | call to rand | Uncontrolled value |
+| test.c:77:9:77:9 | r | test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | call to rand | Uncontrolled value |
+| test.c:83:9:83:9 | r | test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:14:81:17 | call to rand | Uncontrolled value |
+| test.c:83:9:83:9 | r | test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:23:81:26 | call to rand | Uncontrolled value |
| test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value |
| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.c
index 61f39a8e851..bc74725b083 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.c
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.c
@@ -3,12 +3,12 @@
int rand(void);
void trySlice(int start, int end);
+void add_100(int);
#define RAND() rand()
#define RANDN(n) (rand() % n)
#define RAND2() (rand() ^ rand())
-
-
+#define RAND_MAX 32767
@@ -80,7 +80,7 @@ void randomTester() {
{
int r = (rand() ^ rand());
- r = r - 100; // BAD [NOT DETECTED]
+ r = r - 100; // BAD
}
{
@@ -99,4 +99,23 @@ void randomTester() {
*ptr_r = RAND();
r -= 100; // BAD
}
+
+ {
+ int r = rand();
+ r = ((2.0 / (RAND_MAX + 1)) * r - 1.0);
+ add_100(r);
+ }
+}
+
+void add_100(int r) {
+ r += 100; // GOOD
+}
+
+void randomTester2(int bound, int min, int max) {
+ int r1 = rand() % bound;
+ r1 += 100; // GOOD (`bound` may possibly be MAX_INT in which case this could
+ // still overflow, but it's most likely fine)
+
+ int r2 = (rand() % (max - min + 1)) + min;
+ r2 += 100; // GOOD (This is a common way to clamp the random value between [min, max])
}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-327/BrokenCryptoAlgorithm.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-327/BrokenCryptoAlgorithm.expected
index d27d5c4bbca..4232a08ec0f 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-327/BrokenCryptoAlgorithm.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-327/BrokenCryptoAlgorithm.expected
@@ -1,13 +1,16 @@
| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:49:4:49:24 | call to my_des_implementation | call to my_des_implementation |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:62:33:62:40 | ALGO_DES | invocation of macro ALGO_DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:124:4:124:24 | call to my_des_implementation | call to my_des_implementation |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:144:27:144:29 | DES | access of enum constant DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:172:28:172:35 | ALGO_DES | invocation of macro ALGO_DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:175:28:175:34 | USE_DES | access of enum constant USE_DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:182:38:182:45 | ALGO_DES | invocation of macro ALGO_DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:185:38:185:44 | USE_DES | access of enum constant USE_DES |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:238:2:238:20 | call to encrypt | call to encrypt |
-| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:245:5:245:11 | call to encrypt | call to encrypt |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:64:33:64:40 | ALGO_DES | invocation of macro ALGO_DES |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:66:31:66:38 | ALGO_DES | invocation of macro ALGO_DES |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:128:4:128:24 | call to my_des_implementation | call to my_des_implementation |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:148:27:148:29 | DES | access of enum constant DES |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:186:38:186:45 | ALGO_DES | invocation of macro ALGO_DES |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:189:38:189:44 | USE_DES | access of enum constant USE_DES |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:242:2:242:20 | call to encrypt | call to encrypt |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:249:5:249:11 | call to encrypt | call to encrypt |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:304:20:304:37 | call to desEncryptor | call to desEncryptor |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:308:5:308:19 | call to doDesEncryption | call to doDesEncryption |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:309:9:309:23 | call to doDesEncryption | call to doDesEncryption |
+| test2.cpp:49:4:49:24 | call to my_des_implementation | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test2.cpp:403:26:403:45 | call to getEncryptionNameDES | call to doEncryption |
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | invocation of macro ENCRYPT_WITH_DES |
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:39:2:39:31 | ENCRYPT_WITH_RC2(data,amount) | invocation of macro ENCRYPT_WITH_RC2 |
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:41:2:41:32 | ENCRYPT_WITH_3DES(data,amount) | invocation of macro ENCRYPT_WITH_3DES |
@@ -21,5 +24,3 @@
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:91:2:91:12 | call to encrypt3DES | call to encrypt3DES |
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:92:2:92:17 | call to encryptTripleDES | call to encryptTripleDES |
| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:101:2:101:15 | call to do_des_encrypt | call to do_des_encrypt |
-| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:102:2:102:12 | call to DES_Set_Key | call to DES_Set_Key |
-| test.cpp:38:2:38:31 | ENCRYPT_WITH_DES(data,amount) | This file makes use of a broken or weak cryptographic algorithm (specified by $@). | test.cpp:121:2:121:24 | INIT_ENCRYPT_WITH_DES() | invocation of macro INIT_ENCRYPT_WITH_DES |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-327/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-327/test.cpp
index 8af9868f1ee..91af0f7eede 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-327/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-327/test.cpp
@@ -99,7 +99,7 @@ void test_functions(void *data, size_t amount, const char *str)
DoDESEncryption(data, amount); // BAD [NOT DETECTED]
encryptDes(data, amount); // BAD [NOT DETECTED]
do_des_encrypt(data, amount); // BAD
- DES_Set_Key(str); // BAD
+ DES_Set_Key(str); // BAD [NOT DETECTED]
DESSetKey(str); // BAD [NOT DETECTED]
Des(); // GOOD (probably nothing to do with encryption)
@@ -118,7 +118,7 @@ void my_implementation8();
void test_macros2()
{
- INIT_ENCRYPT_WITH_DES(); // BAD
+ INIT_ENCRYPT_WITH_DES(); // BAD [NOT DETECTED]
INIT_ENCRYPT_WITH_AES(); // GOOD (good algorithm)
// ...
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-327/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-327/test2.cpp
index 66d6f283ba3..95fc532c842 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-327/test2.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-327/test2.cpp
@@ -58,8 +58,12 @@ void encrypt_bad(char *data, size_t amount, keytype key, int algo)
void do_encrypts(char *data, size_t amount, keytype key)
{
+ char data2[128];
+
encrypt_good(data, amount, key, ALGO_AES); // GOOD
encrypt_bad(data, amount, key, ALGO_DES); // BAD
+ encrypt_good(data2, 128, key, ALGO_AES); // GOOD
+ encrypt_bad(data2, 128, key, ALGO_DES); // BAD
}
// --- more involved CPP-style example ---
@@ -169,10 +173,10 @@ const char *get_algorithm3();
void do_unseen_encrypts(char *data, size_t amount, keytype key)
{
- set_encryption_algorithm1(ALGO_DES); // BAD
+ set_encryption_algorithm1(ALGO_DES); // BAD [NOT DETECTED]
set_encryption_algorithm1(ALGO_AES); // GOOD
- set_encryption_algorithm2(USE_DES); // BAD
+ set_encryption_algorithm2(USE_DES); // BAD [NOT DETECTED]
set_encryption_algorithm2(USE_AES); // GOOD
set_encryption_algorithm3("DES"); // BAD [NOT DETECTED]
@@ -208,32 +212,32 @@ void do_unseen_encrypts(char *data, size_t amount, keytype key)
class desEncrypt
{
public:
- static void encrypt(const char *data);
+ static void encrypt(char *data);
static void doSomethingElse();
};
class aes256Encrypt
{
public:
- static void encrypt(const char *data);
+ static void encrypt(char *data);
static void doSomethingElse();
};
class desCipher
{
public:
- void encrypt(const char *data);
+ void encrypt(char *data);
void doSomethingElse();
};
class aesCipher
{
public:
- void encrypt(const char *data);
+ void encrypt(char *data);
void doSomethingElse();
};
-void do_classes(const char *data)
+void do_classes(char *data)
{
desEncrypt::encrypt(data); // BAD
aes256Encrypt::encrypt(data); // GOOD
@@ -260,3 +264,142 @@ void do_fn_ptr(char *data, size_t amount, keytype key)
impl = &my_aes_implementation; // GOOD
impl(data, amount, key);
}
+
+// --- template classes ---
+
+class desEncryptor
+{
+public:
+ desEncryptor();
+
+ void doDesEncryption(char *data);
+};
+
+template
+class container
+{
+public:
+ container() {
+ obj = new C(); // GOOD
+ }
+
+ ~container() {
+ delete obj;
+ }
+
+ C *obj;
+};
+
+template
+class templateDesEncryptor
+{
+public:
+ templateDesEncryptor();
+
+ void doDesEncryption(C &data);
+};
+
+void do_template_classes(char *data)
+{
+ desEncryptor *p = new desEncryptor(); // BAD
+ container c; // BAD [NOT DETECTED]
+ templateDesEncryptor t; // BAD [NOT DETECTED]
+
+ p->doDesEncryption(data); // BAD
+ c.obj->doDesEncryption(data); // BAD
+ t.doDesEncryption(data); // BAD [NOT DETECTED]
+}
+
+// --- assert ---
+
+int assertFunc(const char *file, int line);
+#define assert(_cond) ((_cond) || assertFunc(__FILE__, __LINE__))
+
+struct algorithmInfo;
+
+const algorithmInfo *getEncryptionAlgorithmInfo(int algo);
+
+void test_assert(int algo, algorithmInfo *algoInfo)
+{
+ assert(algo != ALGO_DES); // GOOD
+ assert(algoInfo != getEncryptionAlgorithmInfo(ALGO_DES)); // GOOD
+
+ // ...
+}
+
+// --- string comparisons ---
+
+int strcmp(const char *s1, const char *s2);
+void abort(void);
+
+#define ENCRYPTION_DES_NAME "DES"
+#define ENCRYPTION_AES_NAME "AES"
+
+void test_string_comparisons1(const char *algo_name)
+{
+ if (strcmp(algo_name, ENCRYPTION_DES_NAME) == 0) // GOOD
+ {
+ abort();
+ }
+ if (strcmp(algo_name, ENCRYPTION_AES_NAME) == 0) // GOOD
+ {
+ // ...
+ }
+}
+
+const char *getEncryptionNameDES()
+{
+ return "DES";
+}
+
+const char *getEncryptionNameAES()
+{
+ return "AES";
+}
+
+void test_string_comparisons2(const char *algo_name)
+{
+ if (strcmp(algo_name, getEncryptionNameDES()) == 0) // GOOD
+ {
+ abort();
+ }
+ if (strcmp(algo_name, getEncryptionNameAES()) == 0) // GOOD
+ {
+ // ...
+ }
+}
+
+const char *getEncryptionName(int algo)
+{
+ switch (algo)
+ {
+ case ALGO_DES:
+ return getEncryptionNameDES(); // GOOD
+ case ALGO_AES:
+ return getEncryptionNameAES(); // GOOD
+ default:
+ abort();
+ }
+}
+
+void test_string_comparisons3(const char *algo_name)
+{
+ if (strcmp(algo_name, getEncryptionName(ALGO_DES)) == 0) // GOOD
+ {
+ abort();
+ }
+ if (strcmp(algo_name, getEncryptionName(ALGO_AES)) == 0) // GOOD
+ {
+ // ...
+ }
+}
+
+// --- function call in a function call ---
+
+void doEncryption(char *data, size_t len, const char *algorithmName);
+
+void test_fn_in_fn(char *data, size_t len)
+{
+ doEncryption(data, len, getEncryptionNameDES()); // BAD
+ doEncryption(data, len, getEncryptionNameAES()); // GOOD
+}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected
index f514742ff0a..7cf89e8f99f 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected
@@ -1,3 +1,14 @@
+| test2.cpp:39:7:39:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:39:13:39:16 | path | filename | test2.cpp:34:6:34:10 | call to fopen | checked |
+| test2.cpp:52:7:52:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:52:13:52:16 | path | filename | test2.cpp:52:7:52:11 | call to fopen | checked |
+| test2.cpp:69:7:69:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:69:13:69:16 | path | filename | test2.cpp:67:6:67:9 | call to stat | checked |
+| test2.cpp:98:7:98:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:98:13:98:16 | path | filename | test2.cpp:96:15:96:17 | foo | checked |
+| test2.cpp:157:7:157:10 | call to open | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:157:12:157:15 | path | filename | test2.cpp:155:6:155:9 | call to stat | checked |
+| test2.cpp:170:7:170:10 | call to open | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:170:12:170:15 | path | filename | test2.cpp:168:6:168:10 | call to lstat | checked |
+| test2.cpp:245:3:245:7 | call to chmod | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:245:9:245:12 | path | filename | test2.cpp:238:6:238:10 | call to fopen | checked |
+| test2.cpp:255:3:255:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:255:10:255:14 | path1 | filename | test2.cpp:253:6:253:11 | call to rename | checked |
+| test2.cpp:277:7:277:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:277:13:277:16 | path | filename | test2.cpp:275:6:275:11 | call to access | checked |
+| test2.cpp:303:7:303:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:303:13:303:16 | path | filename | test2.cpp:301:7:301:12 | call to access | checked |
+| test2.cpp:317:7:317:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:317:13:317:16 | path | filename | test2.cpp:313:6:313:11 | call to access | checked |
| test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked |
| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked |
| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp
index b876146f571..5d15e1fc3a4 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp
@@ -18,7 +18,7 @@ void test1()
create(file1);
if (!rename(file1, file2))
{
- remove(file1); // BAD
+ remove(file1); // DUBIOUS (bad but perhaps not exploitable) [REPORTED]
}
}
@@ -46,6 +46,6 @@ void test3()
create(file1);
if (!rename(file1, file2))
{
- remove(file1); // BAD
+ remove(file1); // DUBIOUS (bad but perhaps not exploitable) [REPORTED]
}
}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test2.cpp
new file mode 100644
index 00000000000..3d06b3b9e11
--- /dev/null
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test2.cpp
@@ -0,0 +1,333 @@
+// More test cases. Some of these are inspired by real-world cases, others are synthetic or variations.
+
+#define NULL 0
+
+typedef struct {} FILE;
+typedef struct {
+ int foo;
+} stat_data;
+
+FILE *fopen(const char *filename, const char *mode);
+int fclose(FILE *stream);
+
+int open(const char *filename, int arg);
+int creat(const char *filename, int arg);
+int openat(int dir, const char *filename, int arg);
+int close(int file);
+
+bool stat(const char *path, stat_data *buf);
+bool fstat(int file, stat_data *buf);
+bool lstat(const char *path, stat_data *buf);
+bool fstatat(int dir, const char *path, stat_data *buf);
+void chmod(const char *path, int setting);
+int rename(const char *from, const char *to);
+bool remove(const char *path);
+
+bool access(const char *path);
+
+// --- open -> open ---
+
+void test1_1(const char *path)
+{
+ FILE *f = NULL;
+
+ f = fopen(path, "r");
+
+ if (f == NULL)
+ {
+ // retry
+ f = fopen(path, "r"); // GOOD (this is just trying again) [FALSE POSITIVE]
+ }
+
+ // ...
+}
+
+void test1_2(const char *path)
+{
+ FILE *f = NULL;
+
+ // try until we succeed
+ while (f == NULL)
+ {
+ f = fopen(path, "r"); // GOOD (this is just trying again) [FALSE POSITIVE]
+
+ // ...
+ }
+
+ // ...
+}
+
+// --- stat -> open ---
+
+void test2_1(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+
+ if (stat(path, &buf))
+ {
+ f = fopen(path, "r"); // BAD
+ }
+
+ // ...
+}
+
+void test2_2(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+
+ stat(path, &buf);
+ if (buf.foo > 0)
+ {
+ f = fopen(path, "r"); // BAD [NOT DETECTED]
+ }
+
+ // ...
+}
+
+void test2_3(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+ stat_data *buf_ptr = &buf;
+
+ stat(path, buf_ptr);
+ if (buf_ptr->foo > 0)
+ {
+ f = fopen(path, "r"); // BAD
+ }
+
+ // ...
+}
+
+bool stat_condition(const stat_data *buf);
+bool other_condition();
+
+void test2_4(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+
+ stat(path, &buf);
+ if (stat_condition(&buf))
+ {
+ f = fopen(path, "r"); // BAD [NOT DETECTED]
+ }
+
+ // ...
+}
+
+void test2_5(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+ stat_data *buf_ptr = &buf;
+
+ stat(path, buf_ptr);
+ if (stat_condition(buf_ptr))
+ {
+ f = fopen(path, "r"); // BAD [NOT DETECTED]
+ }
+
+ // ...
+}
+
+void test2_6(const char *path)
+{
+ FILE *f = NULL;
+ stat_data buf;
+
+ stat(path, &buf);
+ if (other_condition())
+ {
+ f = fopen(path, "r"); // GOOD (does not depend on the result of stat)
+ }
+
+ // ...
+}
+
+void test2_7(const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ if (stat(path, &buf))
+ {
+ f = open(path, arg); // BAD
+ }
+
+ // ...
+}
+
+void test2_8(const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ if (lstat(path, &buf))
+ {
+ f = open(path, arg); // BAD
+ }
+
+ // ...
+}
+
+void test2_9(const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ if (stat(path, &buf))
+ {
+ f = creat(path, arg); // BAD [NOT DETECTED]
+ }
+
+ // ...
+}
+
+void test2_10(int dir, const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ if (fstatat(dir, path, &buf))
+ {
+ f = openat(dir, path, arg); // BAD [NOT DETECTED]
+ }
+
+ // ...
+}
+
+// --- open -> stat ---
+
+void test3_1(const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ f = open(path, arg);
+ if (stat(path, &buf)) // BAD [NOT DETECTED]
+ {
+ // ...
+ }
+
+ // ...
+}
+
+void test3_2(const char *path, int arg)
+{
+ stat_data buf;
+ int f;
+
+ f = open(path, arg);
+ if (fstat(f, &buf)) // GOOD (uses file descriptor, not path)
+ {
+ // ...
+ }
+
+ // ...
+}
+
+// --- open -> chmod ---
+
+void test4_1(const char *path)
+{
+ FILE *f = NULL;
+
+ f = fopen(path, "w");
+ if (f)
+ {
+ // ...
+
+ fclose(f);
+
+ chmod(path, 0); // DUBIOUS (bad but perhaps not exploitable) [REPORTED]
+ }
+}
+
+// --- rename -> remove / open ---
+
+void test5_1(const char *path1, const char *path2)
+{
+ if (rename(path1, path2))
+ {
+ remove(path1); // DUBIOUS (bad but perhaps not exploitable) [REPORTED]
+ }
+}
+
+void test5_2(const char *path1, const char *path2)
+{
+ FILE *f = NULL;
+
+ if (!rename(path1, path2))
+ {
+ f = fopen(path2, "r"); // BAD [NOT DETECTED]
+ }
+}
+
+// --- access -> open ---
+
+void test6_1(const char *path)
+{
+ FILE *f = NULL;
+
+ if (access(path))
+ {
+ f = fopen(path, "r"); // BAD
+
+ // ...
+ }
+}
+
+void test6_2(const char *path)
+{
+ FILE *f = NULL;
+
+ if (access(path))
+ {
+ // ...
+ }
+
+ f = fopen(path, "r"); // GOOD (appears not to be intended to depend on the access check)
+
+ // ...
+}
+
+void test6_3(const char *path)
+{
+ FILE *f = NULL;
+
+ if (!access(path))
+ {
+ f = fopen(path, "r"); // BAD
+
+ // ...
+ }
+}
+
+void test6_4(const char *path)
+{
+ FILE *f = NULL;
+
+ if (access(path))
+ {
+ // ...
+ } else {
+ f = fopen(path, "r"); // BAD
+
+ // ...
+ }
+}
+
+void test6_5(const char *path1, const char *path2)
+{
+ FILE *f = NULL;
+
+ if (access(path1))
+ {
+ f = fopen(path2, "r"); // GOOD (different file)
+
+ // ...
+ }
+}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseAfterFree.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseAfterFree.expected
index 92aa7a96756..9d8a9d2be24 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseAfterFree.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/UseAfterFree.expected
@@ -7,3 +7,4 @@
| test.cpp:170:6:170:9 | data | Memory pointed to by 'data' may have been previously freed $@ | test.cpp:165:2:165:5 | call to free | here |
| test.cpp:193:6:193:9 | data | Memory pointed to by 'data' may have been previously freed $@ | test.cpp:191:3:191:6 | call to free | here |
| test.cpp:201:6:201:6 | x | Memory pointed to by 'x' may have been previously freed $@ | test.cpp:200:2:200:9 | delete | here |
+| test.cpp:242:14:242:17 | data | Memory pointed to by 'data' may have been previously freed $@ | test.cpp:243:11:243:14 | call to free | here |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/test.cpp
index 7018af457ba..092a430808d 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-416/semmle/tests/test.cpp
@@ -213,3 +213,42 @@ void regression_test_for_static_var_handling()
data = (char *)malloc(100*sizeof(char));
use(data); // GOOD
}
+
+void test16(int n, bool b) {
+ char* data = NULL;
+ for(int i = 0; i < n; ++i) {
+ if(b) data = (char*)malloc(10 * sizeof(char));
+ if(!b || data == NULL) return;
+ use(data); // GOOD
+ free(data); // GOOD
+ }
+}
+
+void test17(int n, bool b) {
+ char* data = (char*)malloc(10);
+ if(b) {
+ free(data);
+ }
+
+ if(!b) {
+ use(data); // GOOD
+ }
+}
+
+void test18(int* array) {
+ char* data = (char*)malloc(10 * sizeof(char));
+ for (int i = 0; i < 4; ++i) {
+ int b = array[i];
+ if(b) use(data); // BAD
+ if(!b) free(data);
+ }
+}
+
+void test19(int* array) {
+ char* data = (char*)malloc(10 * sizeof(char));
+ int b = array[0];
+ for (int i = 0; i < 4; ++i) {
+ if(b) use(data); // GOOD
+ if(!b) free(data);
+ }
+}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/UninitializedLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/UninitializedLocal.expected
index 0c1d750a8f6..985be87585a 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/UninitializedLocal.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/UninitializedLocal.expected
@@ -8,7 +8,6 @@
| test.cpp:132:9:132:9 | j | The variable $@ may not be initialized here. | test.cpp:126:6:126:6 | j | j |
| test.cpp:219:3:219:3 | x | The variable $@ may not be initialized here. | test.cpp:218:7:218:7 | x | x |
| test.cpp:243:13:243:13 | i | The variable $@ may not be initialized here. | test.cpp:241:6:241:6 | i | i |
-| test.cpp:329:9:329:11 | val | The variable $@ may not be initialized here. | test.cpp:321:6:321:8 | val | val |
| test.cpp:336:10:336:10 | a | The variable $@ may not be initialized here. | test.cpp:333:7:333:7 | a | a |
| test.cpp:369:10:369:10 | a | The variable $@ may not be initialized here. | test.cpp:358:7:358:7 | a | a |
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized here. | test.cpp:359:6:359:8 | val | val |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/test.cpp
index d289d223a48..5902c21d6fc 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/test.cpp
@@ -326,7 +326,7 @@ int test28() {
a = false;
c = false;
}
- return val; // GOOD [FALSE POSITIVE]
+ return val; // GOOD
}
int test29() {
diff --git a/csharp/change-notes/2021-06-16-qualified-names.md b/csharp/change-notes/2021-06-16-qualified-names.md
new file mode 100644
index 00000000000..3ecd089402a
--- /dev/null
+++ b/csharp/change-notes/2021-06-16-qualified-names.md
@@ -0,0 +1,9 @@
+lgtm,codescanning
+* The following has changed in `Type::getQualifiedName`/`Type::hasQualifiedName`:
+ - Type parameters now have the qualified name which is simply the name of the type
+ parameter itself. Example: in `class C { }`, `T` has qualified name `T`.
+ - Constructed types now use qualified names for type arguments. For example, the
+ qualified name of `C` is `C`. This also includes array types
+ and pointer types.
+ - Nested types are now delimited by `+` instead of `.`. For example, the qualified
+ name of `Inner` in `class Outer { class Inner { } }` is `Outer+Inner`.
diff --git a/csharp/change-notes/2021-06-24-dataflow-implicit-reads.md b/csharp/change-notes/2021-06-24-dataflow-implicit-reads.md
new file mode 100644
index 00000000000..c96152ed05b
--- /dev/null
+++ b/csharp/change-notes/2021-06-24-dataflow-implicit-reads.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The DataFlow libraries have been augmented with support for `Configuration`-specific in-place read steps at, for example, sinks and custom taint steps. This means that it is now possible to specify sinks that accept flow with non-empty access paths.
diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv
new file mode 100644
index 00000000000..dbac4906d86
--- /dev/null
+++ b/csharp/documentation/library-coverage/coverage.csv
@@ -0,0 +1,2 @@
+package,sink,source,summary,sink:html,sink:xss,source:local,summary:taint
+System,5,3,13,4,1,3,13
diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst
new file mode 100644
index 00000000000..568eadb4cc6
--- /dev/null
+++ b/csharp/documentation/library-coverage/coverage.rst
@@ -0,0 +1,12 @@
+C# framework & library support
+================================
+
+.. csv-table::
+ :header-rows: 1
+ :class: fullWidthTable
+ :widths: auto
+
+ Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
+ System,"``System.*``, ``System``",3,13,5,5
+ Totals,,3,13,5,5
+
diff --git a/csharp/documentation/library-coverage/cwe-sink.csv b/csharp/documentation/library-coverage/cwe-sink.csv
new file mode 100644
index 00000000000..e71e194a2ed
--- /dev/null
+++ b/csharp/documentation/library-coverage/cwe-sink.csv
@@ -0,0 +1,2 @@
+CWE,Sink identifier,Label
+CWE-079,html xss,Cross-site scripting
\ No newline at end of file
diff --git a/csharp/documentation/library-coverage/frameworks.csv b/csharp/documentation/library-coverage/frameworks.csv
new file mode 100644
index 00000000000..d0cc09b4e9c
--- /dev/null
+++ b/csharp/documentation/library-coverage/frameworks.csv
@@ -0,0 +1,2 @@
+Framework name,URL,Namespace prefixes
+System,,System.* System
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs
index f7752f6d60d..8450cd898f8 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs
@@ -108,7 +108,10 @@ namespace Semmle.BuildAnalyser
new[] { options.SolutionFile } :
sourceDir.GetFiles("*.sln", SearchOption.AllDirectories).Select(d => d.FullName);
- RestoreSolutions(solutions);
+ if (options.UseNuGet)
+ {
+ RestoreSolutions(solutions);
+ }
dllDirNames.Add(packageDirectory.DirInfo.FullName);
assemblyCache = new BuildAnalyser.AssemblyCache(dllDirNames, progress);
AnalyseSolutions(solutions);
@@ -289,7 +292,7 @@ namespace Semmle.BuildAnalyser
try
{
- var csProj = new CsProjFile(project);
+ var csProj = new Extraction.CSharp.CsProjFile(project);
foreach (var @ref in csProj.References)
{
@@ -324,7 +327,16 @@ namespace Semmle.BuildAnalyser
private void Restore(string projectOrSolution)
{
- var exit = DotNet.RestoreToDirectory(projectOrSolution, packageDirectory.DirInfo.FullName);
+ int exit;
+ try
+ {
+ exit = DotNet.RestoreToDirectory(projectOrSolution, packageDirectory.DirInfo.FullName);
+ }
+ catch (FileNotFoundException)
+ {
+ exit = 2;
+ }
+
switch (exit)
{
case 0:
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs
index 6d4a2cf07f9..a564d3e7f16 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs
@@ -42,7 +42,5 @@ namespace Semmle.Extraction.CSharp.Entities
public override CommentBlock Create(Context cx, Comments.CommentBlock init) => new CommentBlock(cx, init);
}
-
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs
index f3672e4c6e4..75614d3ad1e 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs
@@ -87,8 +87,6 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";compilation");
}
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
public override Location ReportingLocation => throw new NotImplementedException();
public override bool NeedsPopulation => Context.IsAssemblyScope;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs
index def6edbf5ad..a53ee5797f2 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs
@@ -4,8 +4,6 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Diagnostic : FreshEntity
{
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
private readonly Microsoft.CodeAnalysis.Diagnostic diagnostic;
public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
index e3f77d9407e..525ba96164a 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
@@ -47,7 +47,10 @@ namespace Semmle.Extraction.CSharp.Entities
var baseType = Symbol.ContainingType.BaseType;
if (baseType is null)
{
- Context.ModelError(Symbol, "Unable to resolve base type in implicit constructor initializer");
+ if (Symbol.ContainingType.SpecialType != SpecialType.System_Object)
+ {
+ Context.ModelError(Symbol, "Unable to resolve base type in implicit constructor initializer");
+ }
return;
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs
index ca9753d229b..e88d886efec 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs
@@ -71,7 +71,5 @@ namespace Semmle.Extraction.CSharp.Entities
public override Event Create(Context cx, IEventSymbol init) => new Event(cx, init);
}
-
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs
index 68b108743f3..874d8e1b69f 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs
@@ -43,8 +43,6 @@ namespace Semmle.Extraction.CSharp.Entities
public override Namespace Create(Context cx, INamespaceSymbol init) => new Namespace(cx, init);
}
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
public override int GetHashCode() => QualifiedName.GetHashCode();
private string QualifiedName => Symbol.ToDisplayString();
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs
index b9fd57b2cea..bb5a55e19db 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs
@@ -60,8 +60,6 @@ namespace Semmle.Extraction.CSharp.Entities
new NamespaceDeclaration(cx, init.decl, init.parent);
}
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
public override Microsoft.CodeAnalysis.Location ReportingLocation => node.Name.GetLocation();
public override bool NeedsPopulation => true;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs
index 2ca967a4864..a11b9d94ab5 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs
@@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class DefineDirective : PreprocessorDirective
{
- public DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia)
+ private DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_defines(this, trivia.Name.ToString());
+ trapFile.directive_defines(this, Symbol.Name.ToString());
+ }
+
+ public static DefineDirective Create(Context cx, DefineDirectiveTriviaSyntax def) =>
+ DefineDirectiveFactory.Instance.CreateEntity(cx, def, def);
+
+ private class DefineDirectiveFactory : CachedEntityFactory
+ {
+ public static DefineDirectiveFactory Instance { get; } = new DefineDirectiveFactory();
+
+ public override DefineDirective Create(Context cx, DefineDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs
index ece87fd1f42..9d39bf6461b 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs
@@ -8,21 +8,41 @@ namespace Semmle.Extraction.CSharp.Entities
private readonly IfDirective start;
private readonly int index;
- public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index)
- : base(cx, trivia, populateFromBase: false)
+ private ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index)
+ : base(cx, trivia)
{
this.start = start;
this.index = index;
- TryPopulate();
}
public bool IsTopLevelParent => true;
+ public override void WriteId(EscapingTextWriter trapFile)
+ {
+ trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
+ trapFile.Write(Symbol.IsActive);
+ trapFile.Write(',');
+ trapFile.Write(Symbol.BranchTaken);
+ trapFile.Write(',');
+ trapFile.Write(Symbol.ConditionValue);
+ trapFile.Write(";trivia");
+ }
+
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue, start, index);
+ trapFile.directive_elifs(this, Symbol.BranchTaken, Symbol.ConditionValue, start, index);
- Expression.Create(Context, trivia.Condition, this, 0);
+ Expression.Create(Context, Symbol.Condition, this, 0);
+ }
+
+ public static ElifDirective Create(Context cx, ElifDirectiveTriviaSyntax elif, IfDirective start, int index) =>
+ ElifDirectiveFactory.Instance.CreateEntity(cx, elif, (elif, start, index));
+
+ private class ElifDirectiveFactory : CachedEntityFactory<(ElifDirectiveTriviaSyntax elif, IfDirective start, int index), ElifDirective>
+ {
+ public static ElifDirectiveFactory Instance { get; } = new ElifDirectiveFactory();
+
+ public override ElifDirective Create(Context cx, (ElifDirectiveTriviaSyntax elif, IfDirective start, int index) init) => new(cx, init.elif, init.start, init.index);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs
index 7ab7d45b6e9..1fddae7fbcc 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs
@@ -8,17 +8,35 @@ namespace Semmle.Extraction.CSharp.Entities
private readonly IfDirective start;
private readonly int index;
- public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index)
- : base(cx, trivia, populateFromBase: false)
+ private ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index)
+ : base(cx, trivia)
{
this.start = start;
this.index = index;
- TryPopulate();
+ }
+
+ public override void WriteId(EscapingTextWriter trapFile)
+ {
+ trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
+ trapFile.Write(Symbol.IsActive);
+ trapFile.Write(',');
+ trapFile.Write(Symbol.BranchTaken);
+ trapFile.Write(";trivia");
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_elses(this, trivia.BranchTaken, start, index);
+ trapFile.directive_elses(this, Symbol.BranchTaken, start, index);
+ }
+
+ public static ElseDirective Create(Context cx, ElseDirectiveTriviaSyntax @else, IfDirective start, int index) =>
+ ElseDirectiveFactory.Instance.CreateEntity(cx, @else, (@else, start, index));
+
+ private class ElseDirectiveFactory : CachedEntityFactory<(ElseDirectiveTriviaSyntax @else, IfDirective start, int index), ElseDirective>
+ {
+ public static ElseDirectiveFactory Instance { get; } = new ElseDirectiveFactory();
+
+ public override ElseDirective Create(Context cx, (ElseDirectiveTriviaSyntax @else, IfDirective start, int index) init) => new(cx, init.@else, init.start, init.index);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs
index 9c349844dc6..eb13b62f757 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs
@@ -7,16 +7,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
private readonly IfDirective start;
- public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start)
- : base(cx, trivia, populateFromBase: false)
+ private EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start)
+ : base(cx, trivia)
{
this.start = start;
- TryPopulate();
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endifs(this, start);
}
+
+ public static EndIfDirective Create(Context cx, EndIfDirectiveTriviaSyntax endif, IfDirective start) =>
+ EndIfDirectiveFactory.Instance.CreateEntity(cx, endif, (endif, start));
+
+ private class EndIfDirectiveFactory : CachedEntityFactory<(EndIfDirectiveTriviaSyntax endif, IfDirective start), EndIfDirective>
+ {
+ public static EndIfDirectiveFactory Instance { get; } = new EndIfDirectiveFactory();
+
+ public override EndIfDirective Create(Context cx, (EndIfDirectiveTriviaSyntax endif, IfDirective start) init) => new(cx, init.endif, init.start);
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs
index d4d75470a97..570f9ad61a3 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs
@@ -7,16 +7,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
private readonly RegionDirective region;
- public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region)
- : base(cx, trivia, populateFromBase: false)
+ private EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region)
+ : base(cx, trivia)
{
this.region = region;
- TryPopulate();
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endregions(this, region);
}
+
+ public static EndRegionDirective Create(Context cx, EndRegionDirectiveTriviaSyntax end, RegionDirective start) =>
+ EndRegionDirectiveFactory.Instance.CreateEntity(cx, end, (end, start));
+
+ private class EndRegionDirectiveFactory : CachedEntityFactory<(EndRegionDirectiveTriviaSyntax end, RegionDirective start), EndRegionDirective>
+ {
+ public static EndRegionDirectiveFactory Instance { get; } = new EndRegionDirectiveFactory();
+
+ public override EndRegionDirective Create(Context cx, (EndRegionDirectiveTriviaSyntax end, RegionDirective start) init) => new(cx, init.end, init.start);
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs
index 2917d077839..b0207769bb3 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs
@@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class ErrorDirective : PreprocessorDirective
{
- public ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia)
+ private ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_errors(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
+ trapFile.directive_errors(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
+ }
+
+ public static ErrorDirective Create(Context cx, ErrorDirectiveTriviaSyntax error) =>
+ ErrorDirectiveFactory.Instance.CreateEntity(cx, error, error);
+
+ private class ErrorDirectiveFactory : CachedEntityFactory
+ {
+ public static ErrorDirectiveFactory Instance { get; } = new ErrorDirectiveFactory();
+
+ public override ErrorDirective Create(Context cx, ErrorDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs
index 29c6f741620..415bba4ed5f 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs
@@ -5,18 +5,39 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class IfDirective : PreprocessorDirective, IExpressionParentEntity
{
- public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia)
+ private IfDirective(Context cx, IfDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
public bool IsTopLevelParent => true;
+ public override void WriteId(EscapingTextWriter trapFile)
+ {
+ trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
+ trapFile.Write(Symbol.IsActive);
+ trapFile.Write(',');
+ trapFile.Write(Symbol.BranchTaken);
+ trapFile.Write(',');
+ trapFile.Write(Symbol.ConditionValue);
+ trapFile.Write(";trivia");
+ }
+
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue);
+ trapFile.directive_ifs(this, Symbol.BranchTaken, Symbol.ConditionValue);
- Expression.Create(Context, trivia.Condition, this, 0);
+ Expression.Create(Context, Symbol.Condition, this, 0);
+ }
+
+ public static IfDirective Create(Context cx, IfDirectiveTriviaSyntax @if) =>
+ IfDirectiveFactory.Instance.CreateEntity(cx, @if, @if);
+
+ private class IfDirectiveFactory : CachedEntityFactory
+ {
+ public static IfDirectiveFactory Instance { get; } = new IfDirectiveFactory();
+
+ public override IfDirective Create(Context cx, IfDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs
index 06fafd1e4ce..6afae54a129 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs
@@ -7,34 +7,44 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class LineDirective : PreprocessorDirective
{
- public LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
+ private LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- var type = trivia.Line.Kind() switch
+ var type = Symbol.Line.Kind() switch
{
SyntaxKind.DefaultKeyword => 0,
SyntaxKind.HiddenKeyword => 1,
SyntaxKind.NumericLiteralToken => 2,
- _ => throw new InternalError(trivia, "Unhandled line token kind")
+ _ => throw new InternalError(Symbol, "Unhandled line token kind")
};
trapFile.directive_lines(this, type);
- if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken))
+ if (Symbol.Line.IsKind(SyntaxKind.NumericLiteralToken))
{
- var value = (int)trivia.Line.Value!;
+ var value = (int)Symbol.Line.Value!;
trapFile.directive_line_value(this, value);
- if (!string.IsNullOrWhiteSpace(trivia.File.ValueText))
+ if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
{
- var file = File.Create(Context, trivia.File.ValueText);
+ var file = File.Create(Context, Symbol.File.ValueText);
trapFile.directive_line_file(this, file);
}
}
}
+
+ public static LineDirective Create(Context cx, LineDirectiveTriviaSyntax line) =>
+ LineDirectiveFactory.Instance.CreateEntity(cx, line, line);
+
+ private class LineDirectiveFactory : CachedEntityFactory
+ {
+ public static LineDirectiveFactory Instance { get; } = new LineDirectiveFactory();
+
+ public override LineDirective Create(Context cx, LineDirectiveTriviaSyntax init) => new(cx, init);
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs
index e6bb4e79fed..93372c6200d 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs
@@ -6,30 +6,40 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class NullableDirective : PreprocessorDirective
{
- public NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia)
+ private NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- var setting = trivia.SettingToken.Kind() switch
+ var setting = Symbol.SettingToken.Kind() switch
{
SyntaxKind.DisableKeyword => 0,
SyntaxKind.EnableKeyword => 1,
SyntaxKind.RestoreKeyword => 2,
- _ => throw new InternalError(trivia, "Unhandled setting token kind")
+ _ => throw new InternalError(Symbol, "Unhandled setting token kind")
};
- var target = trivia.TargetToken.Kind() switch
+ var target = Symbol.TargetToken.Kind() switch
{
SyntaxKind.None => 0,
SyntaxKind.AnnotationsKeyword => 1,
SyntaxKind.WarningsKeyword => 2,
- _ => throw new InternalError(trivia, "Unhandled target token kind")
+ _ => throw new InternalError(Symbol, "Unhandled target token kind")
};
trapFile.directive_nullables(this, setting, target);
}
+
+ public static NullableDirective Create(Context cx, NullableDirectiveTriviaSyntax nullable) =>
+ NullableDirectiveFactory.Instance.CreateEntity(cx, nullable, nullable);
+
+ private class NullableDirectiveFactory : CachedEntityFactory
+ {
+ public static NullableDirectiveFactory Instance { get; } = new NullableDirectiveFactory();
+
+ public override NullableDirective Create(Context cx, NullableDirectiveTriviaSyntax init) => new(cx, init);
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs
index caa77ceec33..3e06bba104d 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs
@@ -5,15 +5,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class PragmaChecksumDirective : PreprocessorDirective
{
- public PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia)
+ private PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- var file = File.Create(Context, trivia.File.ValueText);
- trapFile.pragma_checksums(this, file, trivia.Guid.ToString(), trivia.Bytes.ToString());
+ var file = File.Create(Context, Symbol.File.ValueText);
+ trapFile.pragma_checksums(this, file, Symbol.Guid.ToString(), Symbol.Bytes.ToString());
+ }
+
+ public static PragmaChecksumDirective Create(Context cx, PragmaChecksumDirectiveTriviaSyntax p) =>
+ PragmaChecksumDirectiveFactory.Instance.CreateEntity(cx, p, p);
+
+ private class PragmaChecksumDirectiveFactory : CachedEntityFactory
+ {
+ public static PragmaChecksumDirectiveFactory Instance { get; } = new PragmaChecksumDirectiveFactory();
+
+ public override PragmaChecksumDirective Create(Context cx, PragmaChecksumDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs
index 4502fa4a87a..0e4ca37a49f 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs
@@ -7,20 +7,30 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class PragmaWarningDirective : PreprocessorDirective
{
- public PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia)
+ private PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.pragma_warnings(this, trivia.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1);
+ trapFile.pragma_warnings(this, Symbol.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1);
var childIndex = 0;
- foreach (var code in trivia.ErrorCodes)
+ foreach (var code in Symbol.ErrorCodes)
{
trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++);
}
}
+
+ public static PragmaWarningDirective Create(Context cx, PragmaWarningDirectiveTriviaSyntax p) =>
+ PragmaWarningDirectiveFactory.Instance.CreateEntity(cx, p, p);
+
+ private class PragmaWarningDirectiveFactory : CachedEntityFactory
+ {
+ public static PragmaWarningDirectiveFactory Instance { get; } = new PragmaWarningDirectiveFactory();
+
+ public override PragmaWarningDirective Create(Context cx, PragmaWarningDirectiveTriviaSyntax init) => new(cx, init);
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs
index 13e702603ab..dba00d61207 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs
@@ -4,25 +4,16 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
- internal abstract class PreprocessorDirective : FreshEntity where TDirective : DirectiveTriviaSyntax
+ internal abstract class PreprocessorDirective : CachedEntity where TDirective : DirectiveTriviaSyntax
{
- protected readonly TDirective trivia;
+ protected PreprocessorDirective(Context cx, TDirective trivia)
+ : base(cx, trivia) { }
- protected PreprocessorDirective(Context cx, TDirective trivia, bool populateFromBase = true)
- : base(cx)
- {
- this.trivia = trivia;
- if (populateFromBase)
- {
- TryPopulate();
- }
- }
-
- protected sealed override void Populate(TextWriter trapFile)
+ public sealed override void Populate(TextWriter trapFile)
{
PopulatePreprocessor(trapFile);
- trapFile.preprocessor_directive_active(this, trivia.IsActive);
+ trapFile.preprocessor_directive_active(this, Symbol.IsActive);
trapFile.preprocessor_directive_location(this, Context.CreateLocation(ReportingLocation));
if (!Context.Extractor.Standalone)
@@ -34,8 +25,17 @@ namespace Semmle.Extraction.CSharp.Entities
protected abstract void PopulatePreprocessor(TextWriter trapFile);
- public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation();
+ public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetLocation();
+
+ public override bool NeedsPopulation => true;
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
+
+ public override void WriteId(EscapingTextWriter trapFile)
+ {
+ trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
+ trapFile.Write(Symbol.IsActive);
+ trapFile.Write(";trivia");
+ }
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs
index b2f017688a3..f8d963d6192 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs
@@ -6,14 +6,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class RegionDirective : PreprocessorDirective
{
- public RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia)
+ private RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_regions(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
+ trapFile.directive_regions(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
+ }
+
+ public static RegionDirective Create(Context cx, RegionDirectiveTriviaSyntax region) =>
+ RegionDirectiveFactory.Instance.CreateEntity(cx, region, region);
+
+ private class RegionDirectiveFactory : CachedEntityFactory
+ {
+ public static RegionDirectiveFactory Instance { get; } = new RegionDirectiveFactory();
+
+ public override RegionDirective Create(Context cx, RegionDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs
index d4b976d50c0..3bba6699b88 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs
@@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class UndefineDirective : PreprocessorDirective
{
- public UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia)
+ private UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_undefines(this, trivia.Name.ToString());
+ trapFile.directive_undefines(this, Symbol.Name.ToString());
+ }
+
+ public static UndefineDirective Create(Context cx, UndefDirectiveTriviaSyntax undef) =>
+ UndefineDirectiveFactory.Instance.CreateEntity(cx, undef, undef);
+
+ private class UndefineDirectiveFactory : CachedEntityFactory
+ {
+ public static UndefineDirectiveFactory Instance { get; } = new UndefineDirectiveFactory();
+
+ public override UndefineDirective Create(Context cx, UndefDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs
index 1511be8d28c..2f8d2e277dc 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs
@@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class WarningDirective : PreprocessorDirective
{
- public WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia)
+ private WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
- trapFile.directive_warnings(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
+ trapFile.directive_warnings(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
+ }
+
+ public static WarningDirective Create(Context cx, WarningDirectiveTriviaSyntax warning) =>
+ WarningDirectiveFactory.Instance.CreateEntity(cx, warning, warning);
+
+ private class WarningDirectiveFactory : CachedEntityFactory
+ {
+ public static WarningDirectiveFactory Instance { get; } = new WarningDirectiveFactory();
+
+ public override WarningDirective Create(Context cx, WarningDirectiveTriviaSyntax init) => new(cx, init);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
index 9e4a1c79ad2..fd9d0e586fc 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
@@ -2,7 +2,6 @@ using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Entities.Expressions;
-using Semmle.Extraction.Entities;
using Semmle.Extraction.Kinds;
using System.IO;
using System.Linq;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs
index 67936f9a913..2b865d79772 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs
@@ -341,8 +341,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
public override bool Equals(object? obj)
{
var other = obj as Type;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs
index 04ab78a0f54..e71b618bc71 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs
@@ -7,8 +7,6 @@ namespace Semmle.Extraction.CSharp.Entities
public TypeParameterConstraints(Context cx)
: base(cx) { }
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
protected override void Populate(TextWriter trapFile)
{
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs
index d278d904253..0948e1c31bc 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs
@@ -54,7 +54,5 @@ namespace Semmle.Extraction.CSharp.Entities
}
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => node.GetLocation();
-
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs
index 3de3a68b656..907948f2408 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs
@@ -212,8 +212,13 @@ namespace Semmle.Extraction.CSharp
Entities.File.Create(cx, root.SyntaxTree.FilePath);
var csNode = (CSharpSyntaxNode)root;
+ var directiveVisitor = new DirectiveVisitor(cx);
+ csNode.Accept(directiveVisitor);
+ foreach (var branch in directiveVisitor.BranchesTaken)
+ {
+ cx.TrapStackSuffix.Add(branch);
+ }
csNode.Accept(new CompilationUnitVisitor(cx));
- csNode.Accept(new DirectiveVisitor(cx));
cx.PopulateAll();
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
cx.PopulateAll();
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs
similarity index 79%
rename from csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs
rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs
index dc775835e70..385f1cc87c0 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs
@@ -4,12 +4,12 @@ using System.IO;
using System.Linq;
using System.Xml;
-namespace Semmle.BuildAnalyser
+namespace Semmle.Extraction.CSharp
{
///
/// Represents a .csproj file and reads information from it.
///
- internal class CsProjFile
+ public class CsProjFile
{
private string Filename { get; }
@@ -38,14 +38,14 @@ namespace Semmle.BuildAnalyser
// unrecognised content or is the wrong version.
// This currently always fails on Linux because
// Microsoft.Build is not cross platform.
- (csFiles, references) = ReadMsBuildProject(filename);
+ (csFiles, references, projectReferences) = ReadMsBuildProject(filename);
}
catch // lgtm[cs/catch-of-all-exceptions]
{
// There was some reason why the project couldn't be loaded.
// Fall back to reading the Xml document directly.
// This method however doesn't handle variable expansion.
- (csFiles, references) = ReadProjectFileAsXml(filename, Directory);
+ (csFiles, references, projectReferences) = ReadProjectFileAsXml(filename, Directory);
}
}
@@ -55,7 +55,7 @@ namespace Semmle.BuildAnalyser
/// and there seems to be no way to make it succeed. Fails on Linux.
///
/// The file to read.
- private static (string[] csFiles, string[] references) ReadMsBuildProject(FileInfo filename)
+ private static (string[] csFiles, string[] references, string[] projectReferences) ReadMsBuildProject(FileInfo filename)
{
var msbuildProject = new Microsoft.Build.Execution.ProjectInstance(filename.FullName);
@@ -64,13 +64,18 @@ namespace Semmle.BuildAnalyser
.Select(item => item.EvaluatedInclude)
.ToArray();
+ var projectReferences = msbuildProject.Items
+ .Where(item => item.ItemType == "ProjectReference")
+ .Select(item => item.EvaluatedInclude)
+ .ToArray();
+
var csFiles = msbuildProject.Items
.Where(item => item.ItemType == "Compile")
.Select(item => item.GetMetadataValue("FullPath"))
.Where(fn => fn.EndsWith(".cs"))
.ToArray();
- return (csFiles, references);
+ return (csFiles, references, projectReferences);
}
///
@@ -79,7 +84,7 @@ namespace Semmle.BuildAnalyser
/// fallback if ReadMsBuildProject() fails.
///
/// The .csproj file.
- private static (string[] csFiles, string[] references) ReadProjectFileAsXml(FileInfo fileName, string directoryName)
+ private static (string[] csFiles, string[] references, string[] projectReferences) ReadProjectFileAsXml(FileInfo fileName, string directoryName)
{
var projFile = new XmlDocument();
var mgr = new XmlNamespaceManager(projFile.NameTable);
@@ -109,8 +114,16 @@ namespace Semmle.BuildAnalyser
var additionalCsFiles = System.IO.Directory.GetFiles(directoryName, "*.cs", SearchOption.AllDirectories);
+ var projectReferences = root
+ .SelectNodes("/Project/ItemGroup/ProjectReference/@Include", mgr)
+ ?.NodeList()
+ .Select(node => node.Value)
+ .Select(csproj => GetFullPath(csproj, projDir))
+ .Where(s => s is not null)
+ ?? Enumerable.Empty();
+
#nullable disable warnings
- return (explicitCsFiles.Concat(additionalCsFiles).ToArray(), Array.Empty());
+ return (explicitCsFiles.Concat(additionalCsFiles).ToArray(), Array.Empty(), projectReferences.ToArray());
#nullable restore warnings
}
@@ -135,7 +148,7 @@ namespace Semmle.BuildAnalyser
.ToArray();
#nullable disable warnings
- return (csFiles, references);
+ return (csFiles, references, Array.Empty());
#nullable restore warnings
}
@@ -150,6 +163,7 @@ namespace Semmle.BuildAnalyser
}
private readonly string[] references;
+ private readonly string[] projectReferences;
private readonly string[] csFiles;
///
@@ -157,6 +171,11 @@ namespace Semmle.BuildAnalyser
///
public IEnumerable References => references;
+ ///
+ /// The list of project references in full path format.
+ ///
+ public IEnumerable ProjectReferences => projectReferences;
+
///
/// The list of C# source files in full path format.
///
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs
index 1dd6d817b01..d01a3f37ac8 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs
@@ -107,6 +107,11 @@ namespace Semmle.Extraction.CSharp
try
{
+ if (options.ProjectsToLoad.Any())
+ {
+ AddSourceFilesFromProjects(options.ProjectsToLoad, options.CompilerArguments, logger);
+ }
+
var compilerVersion = new CompilerVersion(options);
if (compilerVersion.SkipExtraction)
@@ -146,6 +151,41 @@ namespace Semmle.Extraction.CSharp
}
}
+ private static void AddSourceFilesFromProjects(IEnumerable projectsToLoad, IList compilerArguments, ILogger logger)
+ {
+ logger.Log(Severity.Info, " Loading referenced projects.");
+ var projects = new Queue(projectsToLoad);
+ var processed = new HashSet();
+ while (projects.Count > 0)
+ {
+ var project = projects.Dequeue();
+ var fi = new FileInfo(project);
+ if (processed.Contains(fi.FullName))
+ {
+ continue;
+ }
+
+ processed.Add(fi.FullName);
+ logger.Log(Severity.Info, " Processing referenced project: " + fi.FullName);
+
+ var csProj = new CsProjFile(fi);
+
+ foreach (var cs in csProj.Sources)
+ {
+ if (cs.Contains("/obj/"))
+ {
+ continue;
+ }
+ compilerArguments.Add(cs);
+ }
+
+ foreach (var pr in csProj.ProjectReferences)
+ {
+ projects.Enqueue(pr);
+ }
+ }
+ }
+
///
/// Gets the complete list of locations to locate references.
///
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs
index 981f3d32149..0e27799efd1 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs
@@ -16,6 +16,12 @@ namespace Semmle.Extraction.CSharp
///
public string? Framework { get; set; }
+ ///
+ /// Project files whose source files should be added to the compilation.
+ /// Only used in tests.
+ ///
+ public IList ProjectsToLoad { get; } = new List();
+
///
/// All other arguments passed to the compilation.
///
@@ -68,6 +74,9 @@ namespace Semmle.Extraction.CSharp
case "framework":
Framework = value;
return true;
+ case "load-sources-from-project":
+ ProjectsToLoad.Add(value);
+ return true;
default:
return base.HandleOption(key, value);
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs
index 0c400728554..49b1e96990a 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -8,6 +9,13 @@ namespace Semmle.Extraction.CSharp.Populators
internal class DirectiveVisitor : CSharpSyntaxWalker
{
private readonly Context cx;
+ private readonly List branchesTaken = new();
+
+ ///
+ /// Gets a list of `#if`, `#elif`, and `#else` entities where the branch
+ /// is taken.
+ ///
+ public IEnumerable BranchesTaken => branchesTaken;
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia)
{
@@ -16,49 +24,49 @@ namespace Semmle.Extraction.CSharp.Populators
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node)
{
- new Entities.PragmaWarningDirective(cx, node);
+ Entities.PragmaWarningDirective.Create(cx, node);
}
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node)
{
- new Entities.PragmaChecksumDirective(cx, node);
+ Entities.PragmaChecksumDirective.Create(cx, node);
}
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node)
{
- new Entities.DefineDirective(cx, node);
+ Entities.DefineDirective.Create(cx, node);
}
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node)
{
- new Entities.UndefineDirective(cx, node);
+ Entities.UndefineDirective.Create(cx, node);
}
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node)
{
- new Entities.WarningDirective(cx, node);
+ Entities.WarningDirective.Create(cx, node);
}
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node)
{
- new Entities.ErrorDirective(cx, node);
+ Entities.ErrorDirective.Create(cx, node);
}
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node)
{
- new Entities.NullableDirective(cx, node);
+ Entities.NullableDirective.Create(cx, node);
}
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node)
{
- new Entities.LineDirective(cx, node);
+ Entities.LineDirective.Create(cx, node);
}
private readonly Stack regionStarts = new Stack();
public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node)
{
- var region = new Entities.RegionDirective(cx, node);
+ var region = Entities.RegionDirective.Create(cx, node);
regionStarts.Push(region);
}
@@ -72,7 +80,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = regionStarts.Pop();
- new Entities.EndRegionDirective(cx, node, start);
+ Entities.EndRegionDirective.Create(cx, node, start);
}
private class IfDirectiveStackElement
@@ -91,8 +99,10 @@ namespace Semmle.Extraction.CSharp.Populators
public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node)
{
- var ifStart = new Entities.IfDirective(cx, node);
+ var ifStart = Entities.IfDirective.Create(cx, node);
ifStarts.Push(new IfDirectiveStackElement(ifStart));
+ if (node.BranchTaken)
+ branchesTaken.Add(ifStart);
}
public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node)
@@ -105,7 +115,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Pop();
- new Entities.EndIfDirective(cx, node, start.Entity);
+ Entities.EndIfDirective.Create(cx, node, start.Entity);
}
public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node)
@@ -118,7 +128,9 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Peek();
- new Entities.ElifDirective(cx, node, start.Entity, start.SiblingCount++);
+ var elIf = Entities.ElifDirective.Create(cx, node, start.Entity, start.SiblingCount++);
+ if (node.BranchTaken)
+ branchesTaken.Add(elIf);
}
public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node)
@@ -131,7 +143,9 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Peek();
- new Entities.ElseDirective(cx, node, start.Entity, start.SiblingCount++);
+ var @else = Entities.ElseDirective.Create(cx, node, start.Entity, start.SiblingCount++);
+ if (node.BranchTaken)
+ branchesTaken.Add(@else);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj
index f07ec48d80a..a18d3df87c2 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj
@@ -23,6 +23,7 @@
+
diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs
index 410b3c6980a..abbabcdd198 100644
--- a/csharp/extractor/Semmle.Extraction/Context.cs
+++ b/csharp/extractor/Semmle.Extraction/Context.cs
@@ -30,6 +30,8 @@ namespace Semmle.Extraction
///
public bool ShouldAddAssemblyTrapPrefix { get; }
+ public IList TrapStackSuffix { get; } = new List();
+
private int GetNewId() => TrapWriter.IdCounter++;
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
@@ -270,8 +272,7 @@ namespace Semmle.Extraction
return;
}
- bool duplicationGuard;
- bool deferred;
+ bool duplicationGuard, deferred;
switch (entity.TrapStackBehaviour)
{
@@ -291,14 +292,24 @@ namespace Semmle.Extraction
break;
case TrapStackBehaviour.PushesLabel:
duplicationGuard = true;
- deferred = tagStack.Any();
+ deferred = duplicationGuard && tagStack.Any();
break;
default:
throw new InternalError("Unexpected TrapStackBehaviour");
}
var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc)
- ? (Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer)))
+ ? (() =>
+ {
+ var args = new object[TrapStackSuffix.Count + 2];
+ args[0] = entity;
+ args[1] = loc;
+ for (var i = 0; i < TrapStackSuffix.Count; i++)
+ {
+ args[i + 2] = TrapStackSuffix[i];
+ }
+ WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer));
+ })
: (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer)));
if (deferred)
diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs b/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs
index 88506638e17..4ef36362733 100644
--- a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs
+++ b/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs
@@ -60,7 +60,7 @@ namespace Semmle.Extraction
return other?.GetType() == GetType() && Equals(other.Symbol, Symbol);
}
- public override TrapStackBehaviour TrapStackBehaviour { get; }
+ public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
///
diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs b/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs
index bdef7ac5f66..7ecdab8086e 100644
--- a/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs
+++ b/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs
@@ -33,6 +33,6 @@ namespace Semmle.Extraction
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
- public override TrapStackBehaviour TrapStackBehaviour { get; }
+ public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs
index f7be2995923..99f17537790 100644
--- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs
+++ b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs
@@ -17,7 +17,5 @@ namespace Semmle.Extraction.Entities
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText ?? string.Empty,
msg.Location ?? Context.CreateLocation(), msg.StackTrace ?? string.Empty);
}
-
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs
index 11d37c99636..952302360b1 100644
--- a/csharp/extractor/Semmle.Extraction/Entities/File.cs
+++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs
@@ -24,7 +24,5 @@ namespace Semmle.Extraction.Entities
}
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
-
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}
diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs
index 07e8c805e7f..2826ab49ed1 100644
--- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs
+++ b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs
@@ -33,8 +33,6 @@ namespace Semmle.Extraction.Entities
public override Folder Create(Context cx, PathTransformer.ITransformedPath init) => new Folder(cx, init);
}
- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
-
public override int GetHashCode() => Symbol.GetHashCode();
public override bool Equals(object? obj)
diff --git a/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql b/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
index 09ee699163f..47097fea753 100644
--- a/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
+++ b/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
@@ -3,7 +3,7 @@
* @description Finds uses of hidden fields on forms
* @kind problem
* @problem.severity recommendation
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cs/web/html-hidden-input
* @tags security
diff --git a/csharp/ql/src/Bad Practices/UseOfSystemOutputStream.qhelp b/csharp/ql/src/Bad Practices/UseOfSystemOutputStream.qhelp
index cc4804526b9..65cab70cab8 100644
--- a/csharp/ql/src/Bad Practices/UseOfSystemOutputStream.qhelp
+++ b/csharp/ql/src/Bad Practices/UseOfSystemOutputStream.qhelp
@@ -6,7 +6,7 @@
Writing directly to system output streams is often used as an unstructured form of logging. A
proper logging mechanism is a better way to direct messages to the desired location and also
ensures that no critical information is leaked to the standard outputs. The rule points out any
-call to the Console.Write*(...) methods and any access to Console.Out or
+call to the Console.Write*(...) methods and any access to Console.Out or
Console.Error.
diff --git a/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql b/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
index e7dee2143c1..9fe53d2cc90 100644
--- a/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
+++ b/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
@@ -3,7 +3,7 @@
* @description Finds empty passwords in configuration files.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @id cs/empty-password-in-configuration
* @tags security
diff --git a/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql b/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
index eb4756ea962..8e4dd77febd 100644
--- a/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
+++ b/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
@@ -3,7 +3,7 @@
* @description Finds passwords in configuration files.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision medium
* @id cs/password-in-configuration
* @tags security
diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
index 4e214c6f6d0..1064a76c2e0 100644
--- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
+++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
@@ -141,20 +141,12 @@ class RelevantDefinition extends AssignableDefinition {
// Ensure that the definition is not in dead code
exists(this.getAControlFlowNode()) and
not this.isMaybeLive() and
- (
- // Allow dead initializer assignments, such as `string s = string.Empty`, but only
- // if the initializer expression assigns a default-like value, and there exists another
- // definition of the same variable
- this.isInitializer()
- implies
- (
- not this.isDefaultLikeInitializer()
- or
- not exists(AssignableDefinition other | other.getTarget() = this.getTarget() |
- other != this
- )
- )
- )
+ // Allow dead initializer assignments, such as `string s = string.Empty`, but only
+ // if the initializer expression assigns a default-like value, and there exists another
+ // definition of the same variable
+ if this.isDefaultLikeInitializer()
+ then this = unique(AssignableDefinition def | def.getTarget() = this.getTarget())
+ else any()
}
}
diff --git a/csharp/ql/src/Input Validation/UseOfFileUpload.ql b/csharp/ql/src/Input Validation/UseOfFileUpload.ql
index 4eb96e2c072..e936962ad51 100644
--- a/csharp/ql/src/Input Validation/UseOfFileUpload.ql
+++ b/csharp/ql/src/Input Validation/UseOfFileUpload.ql
@@ -3,7 +3,7 @@
* @description Finds uses of file upload
* @kind problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/web/file-upload
* @tags security
diff --git a/csharp/ql/src/Input Validation/ValueShadowing.qhelp b/csharp/ql/src/Input Validation/ValueShadowing.qhelp
index 746a7d9736f..8e620fa358e 100644
--- a/csharp/ql/src/Input Validation/ValueShadowing.qhelp
+++ b/csharp/ql/src/Input Validation/ValueShadowing.qhelp
@@ -5,8 +5,8 @@
Relying on HttpRequest to provide access to a particular client variable is not
safe. The HttpRequest class implements an indexer to provide a simplified, combined
-access to its QueryString, Form, Cookies, or
-ServerVariables collections, in that particular order. When searching for a variable, the
+access to its QueryString, Form, Cookies, or
+ServerVariables collections, in that particular order. When searching for a variable, the
first match is returned: QueryString parameters hence supersede values from forms,
cookies and server variables, and so on. This is a serious attack vector since an attacker could
inject a value in the query string that you do not expect, and which supersedes the value of a more
diff --git a/csharp/ql/src/Input Validation/ValueShadowingServerVariable.qhelp b/csharp/ql/src/Input Validation/ValueShadowingServerVariable.qhelp
index 0589752453d..f5cdb7df8d7 100644
--- a/csharp/ql/src/Input Validation/ValueShadowingServerVariable.qhelp
+++ b/csharp/ql/src/Input Validation/ValueShadowingServerVariable.qhelp
@@ -6,7 +6,7 @@
Relying on HttpRequest to provide access to a particular server variable is not
safe as it can be overridden by the client. The HttpRequest class implements an
indexer to provide a simplified, combined access to its QueryString, Form
-, Cookies, or ServerVariables collections, in that particular order.
+, Cookies, or ServerVariables collections, in that particular order.
When searching for a variable, the first match is returned: QueryString parameters
hence supersede values from forms, cookies and server variables, and so on. This is a serious
attack vector since an attacker could inject a value in the query string that you do not expect,
diff --git a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
index 1ee9c4a2bfa..392c3e843d7 100644
--- a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
+++ b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
@@ -5,7 +5,7 @@
* but under some circumstances may also result in incorrect results.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.0
* @precision medium
* @id cs/thread-unsafe-icryptotransform-field-in-class
* @tags concurrency
diff --git a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
index 33f8a8ab47c..7787a1bd622 100644
--- a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
+++ b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
@@ -6,7 +6,7 @@
* but under some circumstances may also result in incorrect results.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.0
* @precision medium
* @id cs/thread-unsafe-icryptotransform-captured-in-lambda
* @tags concurrency
diff --git a/csharp/ql/src/Linq/MissedCastOpportunity.qhelp b/csharp/ql/src/Linq/MissedCastOpportunity.qhelp
index 5bd3c92019a..d4de22226c2 100644
--- a/csharp/ql/src/Linq/MissedCastOpportunity.qhelp
+++ b/csharp/ql/src/Linq/MissedCastOpportunity.qhelp
@@ -6,8 +6,8 @@
Casts are often used when you iterate over a collection of elements of a type that is known to
contain only elements of a different type (possibly more specific). For example, List<Animal
> might refer to a collection of instances of Dog, a class derived from
- Animal. Programmers often write a loop to iterate over the collection and cast each
- Animal in turn to Dog before using it
+Animal. Programmers often write a loop to iterate over the collection and cast each
+Animal in turn to Dog before using it
diff --git a/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql b/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
index c9b2112b488..3bccd9b0331 100644
--- a/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
+++ b/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
@@ -4,7 +4,7 @@
* debug builds provide additional information useful to a malicious attacker.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision very-high
* @id cs/web/debug-binary
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
index 6c58c910089..5a527c96084 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
@@ -4,7 +4,7 @@
* denial-of-service attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @id cs/web/large-max-request-length
* @tags security
* frameworks/asp.net
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
index 362b8a70ebe..f093a888446 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
@@ -3,7 +3,7 @@
* @description ASP.NET pages should not disable the built-in request validation.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @id cs/web/request-validation-disabled
* @tags security
* frameworks/asp.net
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
index a270a5928bb..dd9ed5218ff 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cs/insecure-request-validation-mode
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-016
*/
diff --git a/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql b/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql
index e7de9e936c8..d34c8037e8b 100644
--- a/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql
+++ b/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql
@@ -9,7 +9,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.ExternalAPIs
+import semmle.code.csharp.security.dataflow.ExternalAPIsQuery
from ExternalAPIUsedWithUntrustedData externalAPI
select externalAPI, count(externalAPI.getUntrustedDataNode()) as numberOfUses,
diff --git a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
index cda257234ab..6148f0f6ae9 100644
--- a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
+++ b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cs/serialization-check-bypass
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @tags security
* external/cwe/cwe-20
diff --git a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
index c378e31d8aa..88709f2e0cc 100644
--- a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
+++ b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
@@ -5,13 +5,13 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
import csharp
import semmle.code.csharp.dataflow.TaintTracking
-import semmle.code.csharp.security.dataflow.ExternalAPIs
+import semmle.code.csharp.security.dataflow.ExternalAPIsQuery
import DataFlow::PathGraph
from UntrustedDataToExternalAPIConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql b/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
index bf75ab47904..3e395e747b5 100644
--- a/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
+++ b/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
@@ -3,7 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cs/path-injection
* @tags security
@@ -15,7 +15,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.TaintedPath::TaintedPath
+import semmle.code.csharp.security.dataflow.TaintedPathQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
index 5f6855701ed..f33c54ce6aa 100644
--- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
+++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
@@ -6,14 +6,14 @@
* @kind path-problem
* @id cs/zipslip
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-022
*/
import csharp
-import semmle.code.csharp.security.dataflow.ZipSlip::ZipSlip
+import semmle.code.csharp.security.dataflow.ZipSlipQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration zipTaintTracking, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql b/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
index 7056d3222f2..983189a6c55 100644
--- a/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
@@ -4,7 +4,7 @@
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/command-line-injection
* @tags correctness
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.CommandInjection::CommandInjection
+import semmle.code.csharp.security.dataflow.CommandInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql b/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
index b8264b4d8a1..656b8b51786 100644
--- a/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
@@ -4,7 +4,7 @@
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/stored-command-line-injection
* @tags correctness
@@ -15,7 +15,7 @@
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Stored
-import semmle.code.csharp.security.dataflow.CommandInjection::CommandInjection
+import semmle.code.csharp.security.dataflow.CommandInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
class StoredTaintTrackingConfiguration extends TaintTrackingConfiguration {
diff --git a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
index fcf10553a6a..2286b59b0fe 100644
--- a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
+++ b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
@@ -4,7 +4,7 @@
* scripting vulnerability if the data was originally user-provided.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision medium
* @id cs/web/stored-xss
* @tags security
@@ -14,7 +14,8 @@
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Stored
-import semmle.code.csharp.security.dataflow.XSS::XSS
+import semmle.code.csharp.security.dataflow.XSSQuery
+import semmle.code.csharp.security.dataflow.XSSSinks
import semmle.code.csharp.dataflow.DataFlow2
import DataFlow2::PathGraph
diff --git a/csharp/ql/src/Security Features/CWE-079/XSS.ql b/csharp/ql/src/Security Features/CWE-079/XSS.ql
index d58a7828a6f..8735d89ef50 100644
--- a/csharp/ql/src/Security Features/CWE-079/XSS.ql
+++ b/csharp/ql/src/Security Features/CWE-079/XSS.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision high
* @id cs/web/xss
* @tags security
@@ -13,7 +13,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.XSS::XSS
+import semmle.code.csharp.security.dataflow.XSSQuery
import PathGraph
from XssNode source, XssNode sink, string message
diff --git a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
index fde86253edc..77c9e1dd34b 100644
--- a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
@@ -4,7 +4,7 @@
* of malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision medium
* @id cs/second-order-sql-injection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.SqlInjection
+import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection
import semmle.code.csharp.security.dataflow.flowsources.Stored
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
diff --git a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
index 456e36db36e..09b1e637090 100644
--- a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
@@ -4,7 +4,7 @@
* malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cs/sql-injection
* @tags security
@@ -12,8 +12,10 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.SqlInjection::SqlInjection
+import semmle.code.csharp.security.dataflow.SqlInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
+import semmle.code.csharp.security.dataflow.flowsources.Remote
+import semmle.code.csharp.security.dataflow.flowsources.Local
string getSourceType(DataFlow::Node node) {
result = node.(RemoteFlowSource).getSourceType()
diff --git a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
index e0e667ed8da..3f4eae7a10c 100644
--- a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
@@ -4,7 +4,7 @@
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/ldap-injection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.LDAPInjection::LDAPInjection
+import semmle.code.csharp.security.dataflow.LDAPInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
index 0c705fbce33..2f6b20bad4e 100644
--- a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
@@ -4,7 +4,7 @@
* insertion of malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/stored-ldap-injection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.LDAPInjection::LDAPInjection
+import semmle.code.csharp.security.dataflow.LDAPInjectionQuery
import semmle.code.csharp.security.dataflow.flowsources.Stored
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
diff --git a/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql b/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
index 4e2548895ad..1ad4fad9e41 100644
--- a/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cs/xml-injection
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @tags security
* external/cwe/cwe-091
diff --git a/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql b/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
index 8c711400d61..deac49329b7 100644
--- a/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
@@ -4,7 +4,7 @@
* malicious code.
* @kind path-problem
* @problem.severity error
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cs/code-injection
* @tags security
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.CodeInjection::CodeInjection
+import semmle.code.csharp.security.dataflow.CodeInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
index ca32d21b3cb..9bb38adc895 100644
--- a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
@@ -4,7 +4,7 @@
* malicious user providing an unintended resource.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/resource-injection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.ResourceInjection::ResourceInjection
+import semmle.code.csharp.security.dataflow.ResourceInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
index b13d357980b..3367771e0bf 100644
--- a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
+++ b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
@@ -4,7 +4,7 @@
* schema.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 3.6
+ * @security-severity 4.3
* @precision high
* @id cs/xml/missing-validation
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.MissingXMLValidation::MissingXMLValidation
+import semmle.code.csharp.security.dataflow.MissingXMLValidationQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
index 54b578d3072..9c3b9b21bac 100644
--- a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cs/assembly-path-injection
* @problem.severity error
- * @security-severity 6.0
+ * @security-severity 8.2
* @precision high
* @tags security
* external/cwe/cwe-114
diff --git a/csharp/ql/src/Security Features/CWE-117/LogForging.ql b/csharp/ql/src/Security Features/CWE-117/LogForging.ql
index b7642d4e15a..039af51123e 100644
--- a/csharp/ql/src/Security Features/CWE-117/LogForging.ql
+++ b/csharp/ql/src/Security Features/CWE-117/LogForging.ql
@@ -4,7 +4,7 @@
* insertion of forged log entries by a malicious user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id cs/log-forging
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.LogForging::LogForging
+import semmle.code.csharp.security.dataflow.LogForgingQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
index 263429e6995..57d6e500134 100644
--- a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
+++ b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
@@ -5,7 +5,7 @@
* to return any value.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cs/unvalidated-local-pointer-arithmetic
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql b/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
index 7494412e3b3..d079c4f9ac9 100644
--- a/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
+++ b/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
@@ -4,7 +4,7 @@
* and cause a denial of service.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cs/uncontrolled-format-string
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql b/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
index fa40db533d5..ed3e5da0b1f 100644
--- a/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
+++ b/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
@@ -3,7 +3,7 @@
* @description Transmitting sensitive information to the user is a potential security risk.
* @kind path-problem
* @problem.severity error
- * @security-severity 1.4
+ * @security-severity 4.3
* @precision high
* @id cs/sensitive-data-transmission
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql b/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
index 23e72e4e5e9..34f45c0c64e 100644
--- a/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
+++ b/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
@@ -5,7 +5,7 @@
* developing a subsequent exploit.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 5.4
* @precision high
* @id cs/information-exposure-through-exception
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql b/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
index 323630d0c4e..416608b9115 100644
--- a/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
+++ b/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
@@ -4,7 +4,7 @@
* a global error handler, otherwise they may leak exception information.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/web/missing-global-error-handler
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql b/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
index b19ca4ff1bd..f7eacf40fc8 100644
--- a/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
+++ b/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
@@ -4,7 +4,7 @@
* attacker.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision high
* @id cs/cleartext-storage-of-sensitive-information
* @tags security
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.CleartextStorage::CleartextStorage
+import semmle.code.csharp.security.dataflow.CleartextStorageQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
index ff244adee95..d2e95de43bf 100644
--- a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
+++ b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cs/hardcoded-key
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @tags security
* external/cwe/cwe-320
*/
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.cryptography.EncryptionKeyDataFlow::EncryptionKeyDataFlow
+import semmle.code.csharp.security.cryptography.EncryptionKeyDataFlowQuery
/**
* The creation of a literal byte array.
diff --git a/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql b/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
index 2cabc38aa8b..4de91b9a214 100644
--- a/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
+++ b/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
@@ -4,7 +4,7 @@
* @kind path-problem
* @id cs/hard-coded-symmetric-encryption-key
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-321
*/
diff --git a/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql b/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
index a843008e582..a4f4d63d6ee 100644
--- a/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
+++ b/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @id cs/adding-cert-to-root-store
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-327
*/
diff --git a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
index a16358b1f90..fd4a37f7ee3 100644
--- a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
+++ b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
@@ -4,7 +4,7 @@
* @kind path-problem
* @id cs/insecure-sql-connection
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-327
diff --git a/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql b/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
index fb40413716f..e50566d6ca9 100644
--- a/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
+++ b/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
@@ -4,7 +4,7 @@
* allows a malicious attacker to submit a request on behalf of the user.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cs/web/missing-token-validation
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql b/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
index 20323b66bb9..ac2f945258e 100644
--- a/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
+++ b/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
@@ -4,7 +4,7 @@
* unauthorized persons.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision high
* @id cs/exposure-of-sensitive-information
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.ExposureOfPrivateInformation::ExposureOfPrivateInformation
+import semmle.code.csharp.security.dataflow.ExposureOfPrivateInformationQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql b/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
index 75daa5fc10c..87dab081188 100644
--- a/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
+++ b/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
@@ -5,7 +5,7 @@
* their session.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @id cs/session-reuse
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
index 87757be5400..67f3ae1d7b8 100644
--- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
+++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
@@ -4,7 +4,7 @@
* overlay their own UI on top of the site by using an iframe.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision high
* @id cs/web/missing-x-frame-options
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
index 76035d9fcba..c0d0d7ad00b 100644
--- a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
+++ b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cs/deserialized-delegate
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @tags security
* external/cwe/cwe-502
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 338347c0887..076a82b8a05 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -5,14 +5,14 @@
* @kind problem
* @id cs/unsafe-deserialization
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @tags security
* external/cwe/cwe-502
*/
import csharp
-import semmle.code.csharp.security.dataflow.UnsafeDeserialization::UnsafeDeserialization
+import semmle.code.csharp.security.dataflow.UnsafeDeserializationQuery
from Call deserializeCall, Sink sink
where deserializeCall.getAnArgument() = sink.asExpr()
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 32981563ab6..1b8c6dae91e 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -5,14 +5,14 @@
* @kind path-problem
* @id cs/unsafe-deserialization-untrusted-input
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @tags security
* external/cwe/cwe-502
*/
import csharp
-import semmle.code.csharp.security.dataflow.UnsafeDeserialization::UnsafeDeserialization
+import semmle.code.csharp.security.dataflow.UnsafeDeserializationQuery
import DataFlow::PathGraph
from TaintTrackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql b/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
index 82532ed40e0..9416fa32f0a 100644
--- a/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
+++ b/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
@@ -3,7 +3,7 @@
* @description Directory browsing should not be enabled in production as it can leak sensitive information.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision very-high
* @id cs/web/directory-browse-enabled
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
index 37594e7cf72..18acc7fe193 100644
--- a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
+++ b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
@@ -4,7 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.7
+ * @security-severity 6.1
* @precision high
* @id cs/web/unvalidated-url-redirection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.UrlRedirect::UrlRedirect
+import semmle.code.csharp.security.dataflow.UrlRedirectQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql b/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
index 2b37eb33390..568da9188d5 100644
--- a/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
+++ b/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
@@ -3,7 +3,7 @@
* @description Untrusted XML is read with an insecure resolver and DTD processing enabled.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.1
* @precision high
* @id cs/xml/insecure-dtd-handling
* @tags security
@@ -13,7 +13,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.XMLEntityInjection::XMLEntityInjection
+import semmle.code.csharp.security.dataflow.XMLEntityInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
index 1073c873d8c..3b200426399 100644
--- a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
+++ b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
@@ -4,7 +4,7 @@
* be restricted using a secure resolver or disabling DTD processing.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.1
* @precision low
* @id cs/insecure-xml-read
* @tags security
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.xml.InsecureXML::InsecureXML
+import semmle.code.csharp.security.xml.InsecureXMLQuery
from InsecureXmlProcessing xmlProcessing, string reason
where xmlProcessing.isUnsafe(reason)
diff --git a/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql b/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
index 49dd6e52e13..3e5e64ca22e 100644
--- a/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
+++ b/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
@@ -5,7 +5,7 @@
* is used at all times.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/web/requiressl-not-set
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql b/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
index 5d3ee1db4e7..651ffa15f4f 100644
--- a/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
@@ -4,7 +4,7 @@
* user is vulnerable to insertion of malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/xml/stored-xpath-injection
* @tags security
@@ -13,7 +13,7 @@
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Stored
-import semmle.code.csharp.security.dataflow.XPathInjection
+import semmle.code.csharp.security.dataflow.XPathInjectionQuery as XPathInjection
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
class StoredTaintTrackingConfiguration extends XPathInjection::TaintTrackingConfiguration {
diff --git a/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql b/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
index a158ccfab69..8bcf350f594 100644
--- a/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
@@ -4,7 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/xml/xpath-injection
* @tags security
@@ -12,7 +12,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.XPathInjection::XPathInjection
+import semmle.code.csharp.security.dataflow.XPathInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
index 79ade61af90..7355966e4cd 100644
--- a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
+++ b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
@@ -4,7 +4,7 @@
* exponential time on certain input.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/redos
* @tags security
@@ -13,7 +13,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.ReDoS::ReDoS
+import semmle.code.csharp.security.dataflow.ReDoSQuery
import semmle.code.csharp.frameworks.system.text.RegularExpressions
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
diff --git a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
index 5aca2ad9c49..0ce1459091e 100644
--- a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
@@ -5,7 +5,7 @@
* exponential time on certain inputs.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/regex-injection
* @tags security
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.RegexInjection::RegexInjection
+import semmle.code.csharp.security.dataflow.RegexInjectionQuery
import semmle.code.csharp.frameworks.system.text.RegularExpressions
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
index 0aa5f9026d1..f37cd452a58 100644
--- a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
+++ b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
@@ -3,7 +3,7 @@
* @description Credentials are hard-coded in a connection string in the source code of the application.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/hardcoded-connection-string-credentials
* @tags security
@@ -14,13 +14,13 @@
import csharp
import semmle.code.csharp.frameworks.system.Data
-import semmle.code.csharp.security.dataflow.HardcodedCredentials
+import semmle.code.csharp.security.dataflow.HardcodedCredentialsQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
/**
* A string literal containing a username or password field.
*/
-class ConnectionStringPasswordOrUsername extends HardcodedCredentials::NonEmptyStringLiteral {
+class ConnectionStringPasswordOrUsername extends NonEmptyStringLiteral {
ConnectionStringPasswordOrUsername() {
this.getExpr().getValue().regexpMatch("(?i).*(Password|PWD|User Id|UID)=.+")
}
@@ -41,9 +41,7 @@ class ConnectionStringTaintTrackingConfiguration extends TaintTracking::Configur
any(SystemDataConnectionClass connection).getConnectionStringProperty().getAnAssignedValue()
}
- override predicate isSanitizer(DataFlow::Node node) {
- node instanceof HardcodedCredentials::StringFormatSanitizer
- }
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof StringFormatSanitizer }
}
from
diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
index 7b183189921..b55e9dddbfe 100644
--- a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
+++ b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
@@ -3,7 +3,7 @@
* @description Credentials are hard coded in the source code of the application.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/hardcoded-credentials
* @tags security
@@ -13,7 +13,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.HardcodedCredentials::HardcodedCredentials
+import semmle.code.csharp.security.dataflow.HardcodedCredentialsQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from
diff --git a/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql b/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
index 3922c262031..3bdb1f6c7bd 100644
--- a/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
+++ b/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
@@ -4,7 +4,7 @@
* passing through authentication systems.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cs/user-controlled-bypass
* @tags security
@@ -14,7 +14,7 @@
*/
import csharp
-import semmle.code.csharp.security.dataflow.ConditionalBypass::UserControlledBypassOfSensitiveMethod
+import semmle.code.csharp.security.dataflow.ConditionalBypassQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
diff --git a/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql b/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
index 8b8bd478031..8dded310197 100644
--- a/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
+++ b/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
@@ -4,7 +4,7 @@
* pose a security risk.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision low
* @id cs/inappropriate-encoding
* @tags security
@@ -16,9 +16,9 @@ import semmle.code.csharp.frameworks.System
import semmle.code.csharp.frameworks.system.Net
import semmle.code.csharp.frameworks.system.Web
import semmle.code.csharp.frameworks.system.web.UI
-import semmle.code.csharp.security.dataflow.SqlInjection
+import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection
import semmle.code.csharp.security.dataflow.flowsinks.Html
-import semmle.code.csharp.security.dataflow.UrlRedirect
+import semmle.code.csharp.security.dataflow.UrlRedirectQuery as UrlRedirect
import semmle.code.csharp.security.Sanitizers
import semmle.code.csharp.dataflow.DataFlow2::DataFlow2
import semmle.code.csharp.dataflow.DataFlow2::DataFlow2::PathGraph
diff --git a/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql b/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
index 472a87441ed..ca59bd42bdc 100644
--- a/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
+++ b/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
@@ -3,7 +3,7 @@
* @description Finds cookies with an overly broad domain.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 9.3
* @precision high
* @id cs/web/broad-cookie-domain
* @tags security
diff --git a/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql b/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
index ec6953f72e1..bfb2f24f360 100644
--- a/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
+++ b/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
@@ -3,7 +3,7 @@
* @description Finds cookies with an overly broad path.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 9.3
* @precision high
* @id cs/web/broad-cookie-path
* @tags security
diff --git a/csharp/ql/src/Security Features/Encryption using ECB.ql b/csharp/ql/src/Security Features/Encryption using ECB.ql
index 72c63b9c565..ec9719aa781 100644
--- a/csharp/ql/src/Security Features/Encryption using ECB.ql
+++ b/csharp/ql/src/Security Features/Encryption using ECB.ql
@@ -3,7 +3,7 @@
* @description Highlights uses of the encryption mode 'CipherMode.ECB'. This mode should normally not be used because it is vulnerable to replay attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/ecb-encryption
* @tags security
diff --git a/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql b/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
index 94d01609100..631b408a5a3 100644
--- a/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
+++ b/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
@@ -3,7 +3,7 @@
* @description Finds places where header checking is disabled.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.1
* @precision high
* @id cs/web/disabled-header-checking
* @tags security
diff --git a/csharp/ql/src/Security Features/InadequateRSAPadding.ql b/csharp/ql/src/Security Features/InadequateRSAPadding.ql
index ddeb9b370f6..2968b39b6b3 100644
--- a/csharp/ql/src/Security Features/InadequateRSAPadding.ql
+++ b/csharp/ql/src/Security Features/InadequateRSAPadding.ql
@@ -3,7 +3,7 @@
* @description Finds uses of RSA encryption with inadequate padding.
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/inadequate-rsa-padding
* @tags security
diff --git a/csharp/ql/src/Security Features/InsecureRandomness.ql b/csharp/ql/src/Security Features/InsecureRandomness.ql
index 434f8c287f2..b618bff07a5 100644
--- a/csharp/ql/src/Security Features/InsecureRandomness.ql
+++ b/csharp/ql/src/Security Features/InsecureRandomness.ql
@@ -5,7 +5,7 @@
* be generated.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id cs/insecure-randomness
* @tags security
diff --git a/csharp/ql/src/Security Features/InsufficientKeySize.ql b/csharp/ql/src/Security Features/InsufficientKeySize.ql
index 70caea4b179..9829d1dcf4d 100644
--- a/csharp/ql/src/Security Features/InsufficientKeySize.ql
+++ b/csharp/ql/src/Security Features/InsufficientKeySize.ql
@@ -3,7 +3,7 @@
* @description Finds uses of encryption algorithms with too small a key size
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/insufficient-key-size
* @tags security
diff --git a/csharp/ql/src/Security Features/PersistentCookie.ql b/csharp/ql/src/Security Features/PersistentCookie.ql
index c7041cb7a36..be99e63b906 100644
--- a/csharp/ql/src/Security Features/PersistentCookie.ql
+++ b/csharp/ql/src/Security Features/PersistentCookie.ql
@@ -3,7 +3,7 @@
* @description Persistent cookies are vulnerable to attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.2
* @precision high
* @id cs/web/persistent-cookie
* @tags security
diff --git a/csharp/ql/src/Security Features/WeakEncryption.ql b/csharp/ql/src/Security Features/WeakEncryption.ql
index b6d543d6de7..9bf7fae7356 100644
--- a/csharp/ql/src/Security Features/WeakEncryption.ql
+++ b/csharp/ql/src/Security Features/WeakEncryption.ql
@@ -3,7 +3,7 @@
* @description Finds uses of encryption algorithms that are weak and obsolete
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/weak-encryption
* @tags security
diff --git a/csharp/ql/src/Stubs/AllStubsFromReference.ql b/csharp/ql/src/Stubs/AllStubsFromReference.ql
new file mode 100644
index 00000000000..e8d0debb316
--- /dev/null
+++ b/csharp/ql/src/Stubs/AllStubsFromReference.ql
@@ -0,0 +1,15 @@
+/**
+ * Tool to generate C# stubs from a qltest snapshot.
+ */
+
+import csharp
+import Stubs
+
+/** All public declarations from assemblies. */
+class AllExternalPublicDeclarations extends GeneratedDeclaration {
+ AllExternalPublicDeclarations() { this.fromLibrary() }
+}
+
+from Assembly a
+select a.getFullName(), a.getName(), a.getVersion().toString(), a.getFile().getAbsolutePath(),
+ generatedCode(a)
diff --git a/csharp/ql/src/Stubs/AllStubsFromSource.ql b/csharp/ql/src/Stubs/AllStubsFromSource.ql
new file mode 100644
index 00000000000..1a8a816b72f
--- /dev/null
+++ b/csharp/ql/src/Stubs/AllStubsFromSource.ql
@@ -0,0 +1,22 @@
+/**
+ * Tool to generate C# stubs from a qltest snapshot.
+ */
+
+import csharp
+import Stubs
+
+/** All public declarations from source. */
+class AllDeclarations extends GeneratedDeclaration {
+ AllDeclarations() { not this.fromLibrary() }
+}
+
+/** Exclude types from these standard assemblies. */
+private class DefaultLibs extends ExcludedAssembly {
+ DefaultLibs() {
+ this.getName() = "System.Private.CoreLib" or
+ this.getName() = "mscorlib" or
+ this.getName() = "System.Runtime"
+ }
+}
+
+select concat(generatedCode(_) + "\n\n")
diff --git a/csharp/ql/src/Stubs/MinimalStubsFromSource.ql b/csharp/ql/src/Stubs/MinimalStubsFromSource.ql
index c4311b40ac2..14df8576caa 100644
--- a/csharp/ql/src/Stubs/MinimalStubsFromSource.ql
+++ b/csharp/ql/src/Stubs/MinimalStubsFromSource.ql
@@ -29,4 +29,13 @@ class UsedInSource extends GeneratedDeclaration {
}
}
-select generatedCode()
+/** Exclude types from these standard assemblies. */
+private class DefaultLibs extends ExcludedAssembly {
+ DefaultLibs() {
+ this.getName() = "System.Private.CoreLib" or
+ this.getName() = "mscorlib" or
+ this.getName() = "System.Runtime"
+ }
+}
+
+select concat(generatedCode(_) + "\n\n")
diff --git a/csharp/ql/src/Stubs/Stubs.qll b/csharp/ql/src/Stubs/Stubs.qll
index 82bf327215a..4a178980a52 100644
--- a/csharp/ql/src/Stubs/Stubs.qll
+++ b/csharp/ql/src/Stubs/Stubs.qll
@@ -12,6 +12,8 @@
*/
import csharp
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.dotnet.DotNet as DotNet // added to handle VoidType as a ValueOrRefType
/** An element that should be in the generated code. */
abstract class GeneratedElement extends Element { }
@@ -19,44 +21,80 @@ abstract class GeneratedElement extends Element { }
/** A member that should be in the generated code. */
abstract class GeneratedMember extends Member, GeneratedElement { }
+/** Class representing all `struct`s, such as user defined ones and built-in ones, like `int`. */
+private class StructExt extends Type {
+ StructExt() {
+ this instanceof Struct or
+ this instanceof SimpleType or
+ this instanceof VoidType or
+ this instanceof SystemIntPtrType
+ }
+}
+
/** A type that should be in the generated code. */
-abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
+abstract private class GeneratedType extends Type, GeneratedElement {
GeneratedType() {
(
this instanceof Interface
or
this instanceof Class
or
- this instanceof Struct
+ this instanceof StructExt
or
this instanceof Enum
or
this instanceof DelegateType
) and
not this instanceof ConstructedType and
- not this.getALocation() instanceof ExcludedAssembly and
- this.fromLibrary()
+ not this.getALocation() instanceof ExcludedAssembly
}
/**
- * Holds if this type is duplicated in another assembly.
- * In this case, we use the assembly with the highest string.
+ * Holds if this type is defined in multiple assemblies, and at least one of
+ * them is in the `Microsoft.NETCore.App.Ref` folder. In this case, we only stub
+ * the type in the assembly in `Microsoft.NETCore.App.Ref`. In case there are
+ * multiple assemblies in this folder, then we prefer `System.Runtime`.
*/
- private predicate isDuplicate() {
- exists(GeneratedType dup |
- dup.getQualifiedName() = this.getQualifiedName() and
- this.getLocation().(Assembly).toString() < dup.getLocation().(Assembly).toString()
+ private predicate isDuplicate(Assembly assembly) {
+ // type exists in multiple assemblies
+ count(this.getALocation().(Assembly)) > 1 and
+ // at least one of them is in the `Microsoft.NETCore.App.Ref` folder
+ this.getALocation()
+ .(Assembly)
+ .getFile()
+ .getAbsolutePath()
+ .matches("%Microsoft.NETCore.App.Ref%") and
+ exists(int i |
+ i =
+ count(Assembly a |
+ this.getALocation() = a and
+ a.getFile().getAbsolutePath().matches("%Microsoft.NETCore.App.Ref%")
+ )
+ |
+ i = 1 and
+ // assemblies not in `Microsoft.NETCore.App.Ref` folder are considered duplicates
+ not assembly.getFile().getAbsolutePath().matches("%Microsoft.NETCore.App.Ref%")
+ or
+ i > 1 and
+ // one of the assemblies is named `System.Runtime`
+ this.getALocation().(Assembly).getName() = "System.Runtime" and
+ // all others are considered duplicates
+ assembly.getName() != "System.Runtime"
)
}
+ predicate isInAssembly(Assembly assembly) { this.getALocation() = assembly }
+
private string stubKeyword() {
this instanceof Interface and result = "interface"
or
- this instanceof Struct and result = "struct"
+ this instanceof StructExt and result = "struct"
or
this instanceof Class and result = "class"
or
this instanceof Enum and result = "enum"
+ or
+ this instanceof DelegateType and result = "delegate"
}
private string stubAbstractModifier() {
@@ -67,8 +105,16 @@ abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
if this.isStatic() then result = "static " else result = ""
}
+ private string stubPartialModifier() {
+ if
+ count(Assembly a | this.getALocation() = a) <= 1 or
+ this instanceof Enum
+ then result = ""
+ else result = "partial "
+ }
+
private string stubAttributes() {
- if this.getAnAttribute().getType().getQualifiedName() = "System.FlagsAttribute"
+ if this.(ValueOrRefType).getAnAttribute().getType().getQualifiedName() = "System.FlagsAttribute"
then result = "[System.Flags]\n"
else result = ""
}
@@ -76,29 +122,39 @@ abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
private string stubComment() {
result =
"// Generated from `" + this.getQualifiedName() + "` in `" +
- min(this.getLocation().toString()) + "`\n"
- }
-
- private string stubAccessibilityModifier() {
- if this.isPublic() then result = "public " else result = ""
+ concat(this.getALocation().toString(), "; ") + "`\n"
}
/** Gets the entire C# stub code for this type. */
- final string getStub() {
- if this.isDuplicate()
- then result = ""
- else
+ pragma[nomagic]
+ final string getStub(Assembly assembly) {
+ if this.isDuplicate(assembly)
+ then
result =
- this.stubComment() + this.stubAttributes() + this.stubAbstractModifier() +
- this.stubStaticModifier() + this.stubAccessibilityModifier() + this.stubKeyword() + " " +
- this.getUndecoratedName() + stubGenericArguments(this) + stubBaseTypesString() +
- stubTypeParametersConstraints(this) + "\n{\n" + stubMembers() + "}\n\n"
+ "/* Duplicate type '" + this.getName() + "' is not stubbed in this assembly '" +
+ assembly.toString() + "'. */\n\n"
+ else (
+ not this instanceof DelegateType and
+ result =
+ this.stubComment() + this.stubAttributes() + stubAccessibility(this) +
+ this.stubAbstractModifier() + this.stubStaticModifier() + this.stubPartialModifier() +
+ this.stubKeyword() + " " + this.getUndecoratedName() + stubGenericArguments(this) +
+ this.stubBaseTypesString() + stubTypeParametersConstraints(this) + "\n{\n" +
+ this.stubPrivateConstructor() + this.stubMembers(assembly) + "}\n\n"
+ or
+ result =
+ this.stubComment() + this.stubAttributes() + stubUnsafe(this) + stubAccessibility(this) +
+ this.stubKeyword() + " " + stubClassName(this.(DelegateType).getReturnType()) + " " +
+ this.getUndecoratedName() + stubGenericArguments(this) + "(" + stubParameters(this) +
+ ");\n\n"
+ )
}
private ValueOrRefType getAnInterestingBaseType() {
- result = this.getABaseType() and
+ result = this.(ValueOrRefType).getABaseType() and
not result instanceof ObjectType and
- not result.getQualifiedName() = "System.ValueType"
+ not result.getQualifiedName() = "System.ValueType" and
+ (not result instanceof Interface or result.(Interface).isEffectivelyPublic())
}
private string stubBaseTypesString() {
@@ -118,10 +174,49 @@ abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
else result = ""
}
- private string stubMembers() { result = concat(stubMember(this.getAGeneratedMember())) }
+ language[monotonicAggregates]
+ private string stubMembers(Assembly assembly) {
+ result =
+ concat(GeneratedMember m |
+ m = this.getAGeneratedMember(assembly)
+ |
+ stubMember(m, assembly) order by m.getName()
+ )
+ }
+
+ string stubPrivateConstructor() {
+ if
+ this instanceof Interface
+ or
+ this.isStatic()
+ or
+ this.isAbstract()
+ or
+ exists(this.(ValueOrRefType).getAConstructor())
+ or
+ not exists(this.getAnInterestingBaseType())
+ or
+ not exists(this.getAnInterestingBaseType().getAConstructor())
+ or
+ exists(Constructor bc |
+ bc = this.getAnInterestingBaseType().getAConstructor() and
+ bc.getNumberOfParameters() = 0 and
+ not bc.isStatic()
+ )
+ then result = ""
+ else
+ result =
+ " private " + this.getUndecoratedName() + "() : base(" +
+ stubDefaultArguments(getBaseConstructor(this), this) + ")" + " => throw null;\n"
+ }
private GeneratedMember getAGeneratedMember() { result.getDeclaringType() = this }
+ pragma[noinline]
+ private GeneratedMember getAGeneratedMember(Assembly assembly) {
+ result = this.getAGeneratedMember() and assembly = result.getALocation()
+ }
+
final Type getAGeneratedType() {
result = getAnInterestingBaseType()
or
@@ -140,13 +235,15 @@ abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
* This is extended in client code to identify the actual
* declarations that should be generated.
*/
-abstract class GeneratedDeclaration extends Declaration { }
+abstract class GeneratedDeclaration extends Modifiable {
+ GeneratedDeclaration() { this.isEffectivelyPublic() }
+}
private class IndirectType extends GeneratedType {
IndirectType() {
- this.getASubType() instanceof GeneratedType
+ this.(ValueOrRefType).getASubType() instanceof GeneratedType
or
- this.getAChildType() instanceof GeneratedType
+ this.(ValueOrRefType).getAChildType() instanceof GeneratedType
or
this.(UnboundGenericType).getAConstructedGeneric().getASubType() instanceof GeneratedType
or
@@ -192,6 +289,28 @@ private class InheritedMember extends GeneratedMember, Virtualizable {
}
}
+private class ExtraGeneratedConstructor extends GeneratedMember, Constructor {
+ ExtraGeneratedConstructor() {
+ not this.isStatic() and
+ not this.isEffectivelyPublic() and
+ this.getDeclaringType() instanceof GeneratedType and
+ (
+ // if the base class has no 0 parameter constructor
+ not exists(Constructor c |
+ c = this.getDeclaringType().getBaseClass().getAMember() and
+ c.getNumberOfParameters() = 0 and
+ not c.isStatic()
+ )
+ or
+ // if this constructor might be called from a (generic) derived class
+ exists(Class c |
+ this.getDeclaringType() = c.getBaseClass().getUnboundDeclaration() and
+ this = getBaseConstructor(c).getUnboundDeclaration()
+ )
+ )
+ }
+}
+
/** A namespace that contains at least one generated type. */
private class GeneratedNamespace extends Namespace, GeneratedElement {
GeneratedNamespace() {
@@ -208,8 +327,9 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
private string getPostAmble() { if this.isGlobalNamespace() then result = "" else result = "}\n" }
- final string getStubs() {
- result = getPreamble() + getTypeStubs() + getSubNamespaces() + getPostAmble()
+ final string getStubs(Assembly assembly) {
+ result =
+ getPreamble() + getTypeStubs(assembly) + getSubNamespaceStubs(assembly) + getPostAmble()
}
/** Gets the `n`th generated child namespace, indexed from 0. */
@@ -224,14 +344,32 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
result = count(GeneratedNamespace g | g.getParentNamespace() = this)
}
- language[monotonicAggregates]
- private string getSubNamespaces() {
- result = concat(int i | exists(getChildNamespace(i)) | getChildNamespace(i).getStubs())
+ private predicate isInAssembly(Assembly assembly) {
+ any(GeneratedType gt | gt.(DotNet::ValueOrRefType).getDeclaringNamespace() = this)
+ .isInAssembly(assembly)
+ or
+ this.getChildNamespace(_).isInAssembly(assembly)
}
- private string getTypeStubs() {
+ language[monotonicAggregates]
+ string getSubNamespaceStubs(Assembly assembly) {
+ this.isInAssembly(assembly) and
result =
- concat(string s | s = any(GeneratedType gt | gt.getDeclaringNamespace() = this).getStub())
+ concat(GeneratedNamespace child, int i |
+ child = getChildNamespace(i) and child.isInAssembly(assembly)
+ |
+ child.getStubs(assembly) order by i
+ )
+ }
+
+ string getTypeStubs(Assembly assembly) {
+ this.isInAssembly(assembly) and
+ result =
+ concat(GeneratedType gt |
+ gt.(DotNet::ValueOrRefType).getDeclaringNamespace() = this and gt.isInAssembly(assembly)
+ |
+ gt.getStub(assembly) order by gt.getName()
+ )
}
}
@@ -241,26 +379,35 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
*/
abstract class ExcludedAssembly extends Assembly { }
-/** Exclude types from these standard assemblies. */
-private class DefaultLibs extends ExcludedAssembly {
- DefaultLibs() {
- this.getName() = "System.Private.CoreLib" or
- this.getName() = "mscorlib" or
- this.getName() = "System.Runtime"
- }
+private Virtualizable getAccessibilityDeclaringVirtualizable(Virtualizable v) {
+ if not v.isOverride()
+ then result = v
+ else
+ if not v.getOverridee().getLocation() instanceof ExcludedAssembly
+ then result = getAccessibilityDeclaringVirtualizable(v.getOverridee())
+ else result = v
}
private string stubAccessibility(Member m) {
if
- m.getDeclaringType() instanceof Interface or
+ m.getDeclaringType() instanceof Interface
+ or
exists(m.(Virtualizable).getExplicitlyImplementedInterface())
+ or
+ m instanceof Constructor and m.isStatic()
then result = ""
else
if m.isPublic()
then result = "public "
else
if m.isProtected()
- then result = "protected "
+ then
+ if m.isPrivate() or getAccessibilityDeclaringVirtualizable(m).isPrivate()
+ then result = "protected private "
+ else
+ if m.isInternal() or getAccessibilityDeclaringVirtualizable(m).isInternal()
+ then result = "protected internal "
+ else result = "protected "
else
if m.isPrivate()
then result = "private "
@@ -271,7 +418,11 @@ private string stubAccessibility(Member m) {
}
private string stubModifiers(Member m) {
- result = stubAccessibility(m) + stubStaticOrConst(m) + stubOverride(m)
+ result = stubUnsafe(m) + stubAccessibility(m) + stubStaticOrConst(m) + stubOverride(m)
+}
+
+private string stubUnsafe(Member m) {
+ if m.(Modifiable).isUnsafe() then result = "unsafe " else result = ""
}
private string stubStaticOrConst(Member m) {
@@ -291,7 +442,10 @@ private string stubOverride(Member m) {
then result = "virtual "
else
if m.(Virtualizable).isAbstract()
- then result = "abstract "
+ then
+ if m.(Virtualizable).isOverride()
+ then result = "abstract override "
+ else result = "abstract "
else
if m.(Virtualizable).isOverride()
then result = "override "
@@ -303,8 +457,8 @@ private string stubQualifiedNamePrefix(ValueOrRefType t) {
then result = ""
else
if t.getParent() instanceof Namespace
- then result = t.getParent().(Namespace).getQualifiedName() + "."
- else result = stubQualifiedNamePrefix(t.getParent()) + "."
+ then result = t.getDeclaringNamespace().getQualifiedName() + "."
+ else result = stubClassName(t.getDeclaringType()) + "."
}
language[monotonicAggregates]
@@ -344,13 +498,16 @@ private string stubClassName(Type t) {
else
if t instanceof TupleType
then
- result =
- "(" +
- concat(int i, Type element |
- element = t.(TupleType).getElementType(i)
- |
- stubClassName(element), "," order by i
- ) + ")"
+ if t.(TupleType).getArity() < 2
+ then result = stubClassName(t.(TupleType).getUnderlyingType())
+ else
+ result =
+ "(" +
+ concat(int i, Type element |
+ element = t.(TupleType).getElementType(i)
+ |
+ stubClassName(element), "," order by i
+ ) + ")"
else
if t instanceof ValueOrRefType
then
@@ -361,7 +518,7 @@ private string stubClassName(Type t) {
}
language[monotonicAggregates]
-private string stubGenericArguments(ValueOrRefType t) {
+private string stubGenericArguments(Type t) {
if t instanceof UnboundGenericType
then
result =
@@ -397,27 +554,43 @@ private string stubGenericMethodParams(Method m) {
else result = ""
}
-private string stubConstraints(TypeParameterConstraints tpc) {
- tpc.hasConstructorConstraint() and result = "new()"
+private string stubConstraints(TypeParameterConstraints tpc, int i) {
+ tpc.hasConstructorConstraint() and result = "new()" and i = 4
or
- tpc.hasUnmanagedTypeConstraint() and result = "unmanaged"
+ tpc.hasUnmanagedTypeConstraint() and result = "unmanaged" and i = 0
or
- tpc.hasValueTypeConstraint() and result = "struct"
+ tpc.hasValueTypeConstraint() and
+ result = "struct" and
+ i = 0 and
+ not tpc.hasUnmanagedTypeConstraint() and
+ not stubClassName(tpc.getATypeConstraint().(Class)) = "System.Enum"
or
- tpc.hasRefTypeConstraint() and result = "class"
+ tpc.hasRefTypeConstraint() and result = "class" and i = 0
or
- result = tpc.getATypeConstraint().(TypeParameter).getName()
+ result = tpc.getATypeConstraint().(TypeParameter).getName() and i = 3
or
- result = stubClassName(tpc.getATypeConstraint().(Interface))
+ result = stubClassName(tpc.getATypeConstraint().(Interface)) and i = 2
or
- result = stubClassName(tpc.getATypeConstraint().(Class))
+ result = stubClassName(tpc.getATypeConstraint().(Class)) and i = 1
}
private string stubTypeParameterConstraints(TypeParameter tp) {
- exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
- result =
- " where " + tp.getName() + ": " + strictconcat(string s | s = stubConstraints(tpc) | s, ", ")
- )
+ if
+ tp.getDeclaringGeneric().(Virtualizable).isOverride() or
+ tp.getDeclaringGeneric().(Virtualizable).implementsExplicitInterface()
+ then
+ if tp.getConstraints().hasValueTypeConstraint()
+ then result = " where " + tp.getName() + ": struct"
+ else
+ if tp.getConstraints().hasRefTypeConstraint()
+ then result = " where " + tp.getName() + ": class"
+ else result = ""
+ else
+ exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
+ result =
+ " where " + tp.getName() + ": " +
+ strictconcat(string s, int i | s = stubConstraints(tpc, i) | s, ", " order by i)
+ )
}
private string stubTypeParametersConstraints(Declaration d) {
@@ -433,9 +606,7 @@ private string stubTypeParametersConstraints(Declaration d) {
}
private string stubImplementation(Virtualizable c) {
- if c.isAbstract() or c.getDeclaringType() instanceof Interface
- then result = ""
- else result = " => throw null"
+ if c.isAbstract() then result = "" else result = " => throw null"
}
private predicate isKeyword(string s) {
@@ -533,6 +704,17 @@ private string stubParameters(Parameterizable p) {
)
}
+private string stubDefaultArguments(Constructor baseCtor, ValueOrRefType callingType) {
+ baseCtor = getBaseConstructor(callingType) and
+ baseCtor.getNumberOfParameters() > 0 and
+ result =
+ concat(int i, Parameter param |
+ param = baseCtor.getParameter(i) and not param.getType() instanceof ArglistType
+ |
+ "default(" + stubClassName(param.getType()) + ")", ", " order by i
+ )
+}
+
private string stubParameterModifiers(Parameter p) {
if p.isOut()
then result = "out "
@@ -557,58 +739,181 @@ private string stubDefaultValue(Parameter p) {
else result = ""
}
+private string stubEventAccessors(Event e) {
+ if exists(e.(Virtualizable).getExplicitlyImplementedInterface())
+ then result = " { add => throw null; remove => throw null; }"
+ else result = ";"
+}
+
private string stubExplicitImplementation(Member c) {
if exists(c.(Virtualizable).getExplicitlyImplementedInterface())
then result = stubClassName(c.(Virtualizable).getExplicitlyImplementedInterface()) + "."
else result = ""
}
-private string stubMember(Member m) {
- exists(Method c | m = c and not m.getDeclaringType() instanceof Enum |
+pragma[noinline]
+private string stubMethod(Method m, Assembly assembly) {
+ m instanceof GeneratedMember and
+ m.getALocation() = assembly and
+ if not m.getDeclaringType() instanceof Enum
+ then
result =
- " " + stubModifiers(c) + stubClassName(c.getReturnType()) + " " +
- stubExplicitImplementation(c) + c.getName() + stubGenericMethodParams(c) + "(" +
- stubParameters(c) + ")" + stubTypeParametersConstraints(c) + stubImplementation(c) + ";\n"
+ " " + stubModifiers(m) + stubClassName(m.(Method).getReturnType()) + " " +
+ stubExplicitImplementation(m) + m.getName() + stubGenericMethodParams(m) + "(" +
+ stubParameters(m) + ")" + stubTypeParametersConstraints(m) + stubImplementation(m) + ";\n"
+ else result = " // Stub generator skipped method: " + m.getName() + "\n"
+}
+
+pragma[noinline]
+private string stubOperator(Operator o, Assembly assembly) {
+ o instanceof GeneratedMember and
+ o.getALocation() = assembly and
+ if o instanceof ConversionOperator
+ then
+ result =
+ " " + stubModifiers(o) + stubExplicit(o) + "operator " + stubClassName(o.getReturnType()) +
+ "(" + stubParameters(o) + ") => throw null;\n"
+ else
+ if not o.getDeclaringType() instanceof Enum
+ then
+ result =
+ " " + stubModifiers(o) + stubClassName(o.getReturnType()) + " operator " + o.getName() +
+ "(" + stubParameters(o) + ") => throw null;\n"
+ else result = " // Stub generator skipped operator: " + o.getName() + "\n"
+}
+
+pragma[noinline]
+private string stubEnumConstant(EnumConstant ec, Assembly assembly) {
+ ec instanceof GeneratedMember and
+ ec.getALocation() = assembly and
+ result = " " + ec.getName() + ",\n"
+}
+
+pragma[noinline]
+private string stubProperty(Property p, Assembly assembly) {
+ p instanceof GeneratedMember and
+ p.getALocation() = assembly and
+ result =
+ " " + stubModifiers(p) + stubClassName(p.getType()) + " " + stubExplicitImplementation(p) +
+ p.getName() + " { " + stubGetter(p) + stubSetter(p) + "}\n"
+}
+
+pragma[noinline]
+private string stubConstructor(Constructor c, Assembly assembly) {
+ c instanceof GeneratedMember and
+ c.getALocation() = assembly and
+ if c.getDeclaringType() instanceof Enum
+ then result = ""
+ else
+ if
+ not c.getDeclaringType() instanceof StructExt or
+ c.getNumberOfParameters() > 0
+ then
+ result =
+ " " + stubModifiers(c) + c.getName() + "(" + stubParameters(c) + ")" +
+ stubConstructorInitializer(c) + " => throw null;\n"
+ else result = " // Stub generator skipped constructor \n"
+}
+
+pragma[noinline]
+private string stubIndexer(Indexer i, Assembly assembly) {
+ i instanceof GeneratedMember and
+ i.getALocation() = assembly and
+ result =
+ " " + stubIndexerNameAttribute(i) + stubModifiers(i) + stubClassName(i.getType()) + " " +
+ stubExplicitImplementation(i) + "this[" + stubParameters(i) + "] { " + stubGetter(i) +
+ stubSetter(i) + "}\n"
+}
+
+pragma[noinline]
+private string stubField(Field f, Assembly assembly) {
+ f instanceof GeneratedMember and
+ f.getALocation() = assembly and
+ not f instanceof EnumConstant and // EnumConstants are already stubbed
+ exists(string impl |
+ (if f.isConst() then impl = " = default" else impl = "") and
+ result =
+ " " + stubModifiers(f) + stubClassName(f.getType()) + " " + escapeIfKeyword(f.getName()) +
+ impl + ";\n"
+ )
+}
+
+pragma[noinline]
+private string stubEvent(Event e, Assembly assembly) {
+ e instanceof GeneratedMember and
+ e.getALocation() = assembly and
+ result =
+ " " + stubModifiers(e) + "event " + stubClassName(e.getType()) + " " +
+ stubExplicitImplementation(e) + e.getName() + stubEventAccessors(e) + "\n"
+}
+
+pragma[nomagic]
+private string stubMember(GeneratedMember m, Assembly assembly) {
+ result = stubMethod(m, assembly)
+ or
+ result = stubOperator(m, assembly)
+ or
+ result = stubEnumConstant(m, assembly)
+ or
+ result = stubProperty(m, assembly)
+ or
+ result = stubConstructor(m, assembly)
+ or
+ result = stubIndexer(m, assembly)
+ or
+ result = stubField(m, assembly)
+ or
+ result = stubEvent(m, assembly)
+ or
+ not m instanceof Method and
+ not m instanceof Operator and
+ not m instanceof EnumConstant and
+ not m instanceof Property and
+ not m instanceof Constructor and
+ not m instanceof Indexer and
+ not m instanceof Field and
+ not m instanceof Event and
+ m.getALocation() = assembly and
+ (
+ result = m.(GeneratedType).getStub(assembly) + "\n"
+ or
+ not m instanceof GeneratedType and
+ result = " // ERR: Stub generator didn't handle member: " + m.getName() + "\n"
+ )
+}
+
+private string stubIndexerNameAttribute(Indexer i) {
+ if i.getName() != "Item"
+ then result = "[System.Runtime.CompilerServices.IndexerName(\"" + i.getName() + "\")]\n "
+ else result = ""
+}
+
+private Constructor getBaseConstructor(ValueOrRefType type) {
+ result =
+ min(Constructor bc |
+ type.getBaseClass().getAMember() = bc and
+ // not the `static` constructor
+ not bc.isStatic() and
+ // not a `private` constructor, unless it's `private protected`, or if the derived class is nested
+ (not bc.isPrivate() or bc.isProtected() or bc.getDeclaringType() = type.getDeclaringType+())
+ |
+ bc order by bc.getNumberOfParameters(), stubParameters(bc)
+ )
+}
+
+private string stubConstructorInitializer(Constructor c) {
+ exists(Constructor baseCtor |
+ baseCtor = getBaseConstructor(c.getDeclaringType()) and
+ if baseCtor.getNumberOfParameters() = 0 or c.isStatic()
+ then result = ""
+ else result = " : base(" + stubDefaultArguments(baseCtor, c.getDeclaringType()) + ")"
)
or
- exists(Operator op |
- m = op and not m.getDeclaringType() instanceof Enum and not op instanceof ConversionOperator
- |
- result =
- " " + stubModifiers(op) + stubClassName(op.getReturnType()) + " operator " + op.getName() +
- "(" + stubParameters(op) + ") => throw null;\n"
- )
- or
- exists(ConversionOperator op | m = op |
- result =
- " " + stubModifiers(op) + stubExplicit(op) + "operator " +
- stubClassName(op.getReturnType()) + "(" + stubParameters(op) + ") => throw null;\n"
- )
- or
- result = " " + m.(EnumConstant).getName() + ",\n"
- or
- exists(Property p | m = p |
- result =
- " " + stubModifiers(m) + stubClassName(p.getType()) + " " + stubExplicitImplementation(p) +
- p.getName() + " { " + stubGetter(p) + stubSetter(p) + "}\n"
- )
- or
- exists(Constructor c | m = c and not c.getDeclaringType() instanceof Enum |
- result =
- " " + stubModifiers(m) + c.getName() + "(" + stubParameters(c) + ") => throw null;\n"
- )
- or
- exists(Indexer i | m = i |
- result =
- " " + stubModifiers(m) + stubClassName(i.getType()) + " this[" + stubParameters(i) + "] { "
- + stubGetter(i) + stubSetter(i) + "}\n"
- )
- or
- exists(Field f, string impl | f = m and not f instanceof EnumConstant |
- (if f.isConst() then impl = " = throw null" else impl = "") and
- result =
- " " + stubModifiers(m) + stubClassName(f.getType()) + " " + f.getName() + impl + ";\n"
- )
+ // abstract base class might not have a constructor
+ not exists(Constructor baseCtor |
+ c.getDeclaringType().getBaseClass().getAMember() = baseCtor and not baseCtor.isStatic()
+ ) and
+ result = ""
}
private string stubExplicit(ConversionOperator op) {
@@ -619,19 +924,13 @@ private string stubExplicit(ConversionOperator op) {
private string stubGetter(DeclarationWithGetSetAccessors p) {
if exists(p.getGetter())
- then
- if p.isAbstract() or p.getDeclaringType() instanceof Interface
- then result = "get; "
- else result = "get => throw null; "
+ then if p.isAbstract() then result = "get; " else result = "get => throw null; "
else result = ""
}
private string stubSetter(DeclarationWithGetSetAccessors p) {
if exists(p.getSetter())
- then
- if p.isAbstract() or p.getDeclaringType() instanceof Interface
- then result = "set; "
- else result = "set => throw null; "
+ then if p.isAbstract() then result = "set; " else result = "set => throw null; "
else result = ""
}
@@ -647,8 +946,8 @@ private string stubSemmleExtractorOptions() {
}
/** Gets the generated C# code. */
-string generatedCode() {
+string generatedCode(Assembly assembly) {
result =
"// This file contains auto-generated code.\n" + stubSemmleExtractorOptions() + "\n" +
- any(GeneratedNamespace ns | ns.isGlobalNamespace()).getStubs()
+ any(GeneratedNamespace ns | ns.isGlobalNamespace()).getStubs(assembly)
}
diff --git a/csharp/ql/src/Stubs/helpers.py b/csharp/ql/src/Stubs/helpers.py
new file mode 100644
index 00000000000..d48bc3082d9
--- /dev/null
+++ b/csharp/ql/src/Stubs/helpers.py
@@ -0,0 +1,44 @@
+import sys
+import os
+import subprocess
+
+
+def run_cmd(cmd, msg="Failed to run command"):
+ print('Running ' + ' '.join(cmd))
+ if subprocess.check_call(cmd):
+ print(msg)
+ exit(1)
+
+
+def get_argv(index, default):
+ if len(sys.argv) > index:
+ return sys.argv[index]
+ return default
+
+
+def trim_output_file(file):
+ # Remove the leading and trailing bytes from the file
+ length = os.stat(file).st_size
+ if length < 20:
+ contents = b''
+ else:
+ f = open(file, "rb")
+ try:
+ pre = f.read(2)
+ print("Start characters in file skipped.", pre)
+ contents = f.read(length - 5)
+ post = f.read(3)
+ print("End characters in file skipped.", post)
+ finally:
+ f.close()
+
+ f = open(file, "wb")
+ f.write(contents)
+ f.close()
+
+
+# remove all files with extension
+def remove_files(path, ext):
+ for file in os.listdir(path):
+ if file.endswith(ext):
+ os.remove(os.path.join(path, file))
diff --git a/csharp/ql/src/Stubs/make_stubs.py b/csharp/ql/src/Stubs/make_stubs.py
index 7d2ce9f7ed7..e66371f2b95 100644
--- a/csharp/ql/src/Stubs/make_stubs.py
+++ b/csharp/ql/src/Stubs/make_stubs.py
@@ -11,6 +11,7 @@
import sys
import os
import subprocess
+import helpers
print('Script to generate stub.cs files for C# qltest projects')
@@ -45,6 +46,7 @@ if not foundCS:
csharpQueries = os.path.abspath(os.path.dirname(sys.argv[0]))
outputFile = os.path.join(testDir, 'stubs.cs')
+bqrsFile = os.path.join(testDir, 'stubs.bqrs')
print("Stubbing qltest in", testDir)
@@ -52,11 +54,8 @@ if os.path.isfile(outputFile):
os.remove(outputFile) # It would interfere with the test.
print("Removed previous", outputFile)
-cmd = ['codeql', 'test', 'run', '--keep-databases', testDir]
-print('Running ' + ' '.join(cmd))
-if subprocess.check_call(cmd):
- print("codeql test failed. Please fix up the test before proceeding.")
- exit(1)
+helpers.run_cmd(['codeql', 'test', 'run', '--keep-databases', testDir],
+ "codeql test failed. Please fix up the test before proceeding.")
dbDir = os.path.join(testDir, os.path.basename(testDir) + ".testproj")
@@ -64,47 +63,17 @@ if not os.path.isdir(dbDir):
print("Expected database directory " + dbDir + " not found.")
exit(1)
-cmd = ['codeql', 'query', 'run', os.path.join(
- csharpQueries, 'MinimalStubsFromSource.ql'), '--database', dbDir, '--output', outputFile]
-print('Running ' + ' '.join(cmd))
-if subprocess.check_call(cmd):
- print('Failed to run the query to generate output file.')
- exit(1)
+helpers.run_cmd(['codeql', 'query', 'run', os.path.join(
+ csharpQueries, 'MinimalStubsFromSource.ql'), '--database', dbDir, '--output', bqrsFile], 'Failed to run the query to generate output file.')
-# Remove the leading and trailing bytes from the file
-length = os.stat(outputFile).st_size
-if length < 20:
- contents = b''
-else:
- f = open(outputFile, "rb")
- try:
- countTillSlash = 0
- foundSlash = False
- slash = f.read(1)
- while slash != b'':
- if slash == b'/':
- foundSlash = True
- break
- countTillSlash += 1
- slash = f.read(1)
+helpers.run_cmd(['codeql', 'bqrs', 'decode', bqrsFile, '--output',
+ outputFile, '--format=text', '--no-titles'], 'Failed to run the query to generate output file.')
- if not foundSlash:
- countTillSlash = 0
+helpers.trim_output_file(outputFile)
- f.seek(0)
- quote = f.read(countTillSlash)
- print("Start characters in file skipped.", quote)
- post = b'\x0e\x01\x08#select\x01\x01\x00s\x00'
- contents = f.read(length - len(post) - countTillSlash)
- quote = f.read(len(post))
- if quote != post:
- print("Unexpected end character in file.", quote)
- finally:
- f.close()
-
-f = open(outputFile, "wb")
-f.write(contents)
-f.close()
+if os.path.isfile(bqrsFile):
+ os.remove(bqrsFile) # Cleanup
+ print("Removed temp BQRS file", bqrsFile)
cmd = ['codeql', 'test', 'run', testDir]
print('Running ' + ' '.join(cmd))
diff --git a/csharp/ql/src/Stubs/make_stubs_nuget.py b/csharp/ql/src/Stubs/make_stubs_nuget.py
new file mode 100644
index 00000000000..a0acd38f841
--- /dev/null
+++ b/csharp/ql/src/Stubs/make_stubs_nuget.py
@@ -0,0 +1,220 @@
+import sys
+import os
+import helpers
+import json
+import shutil
+
+
+def write_csproj_prefix(ioWrapper):
+ ioWrapper.write('\n')
+ ioWrapper.write(' \n')
+ ioWrapper.write(' net5.0 \n')
+ ioWrapper.write(' true \n')
+ ioWrapper.write(' bin\ \n')
+ ioWrapper.write(
+ ' false \n')
+ ioWrapper.write(' \n\n')
+
+
+print('Script to generate stub file from a nuget package')
+print(' Usage: python ' + sys.argv[0] +
+ ' NUGET_PACKAGE_NAME [VERSION=latest] [WORK_DIR=tempDir]')
+print(' The script uses the dotnet cli, codeql cli, and dotnet format global tool')
+
+if len(sys.argv) < 2:
+ print("\nPlease supply a nuget package name.")
+ exit(1)
+
+thisScript = sys.argv[0]
+thisDir = os.path.abspath(os.path.dirname(thisScript))
+nuget = sys.argv[1]
+
+# /input contains a dotnet project that's being extracted
+workDir = os.path.abspath(helpers.get_argv(3, "tempDir"))
+projectNameIn = "input"
+projectDirIn = os.path.join(workDir, projectNameIn)
+
+# /output contains the output of the stub generation
+outputDirName = "output"
+outputDir = os.path.join(workDir, outputDirName)
+
+# /output/raw contains the bqrs result from the query, the json equivalent
+rawOutputDirName = "raw"
+rawOutputDir = os.path.join(outputDir, rawOutputDirName)
+os.makedirs(rawOutputDir)
+
+# /output/output contains a dotnet project with the generated stubs
+projectNameOut = "output"
+projectDirOut = os.path.join(outputDir, projectNameOut)
+
+# /db contains the extracted QL DB
+dbName = 'db'
+dbDir = os.path.join(workDir, dbName)
+outputName = "stub"
+outputFile = os.path.join(projectDirOut, outputName + '.cs')
+bqrsFile = os.path.join(rawOutputDir, outputName + '.bqrs')
+jsonFile = os.path.join(rawOutputDir, outputName + '.json')
+version = helpers.get_argv(2, "latest")
+
+print("\n* Creating new input project")
+helpers.run_cmd(['dotnet', 'new', 'classlib', "--language", "C#", '--name',
+ projectNameIn, '--output', projectDirIn])
+helpers.remove_files(projectDirIn, '.cs')
+
+print("\n* Adding reference to package: " + nuget)
+cmd = ['dotnet', 'add', projectDirIn, 'package', nuget]
+if (version != "latest"):
+ cmd.append('--version')
+ cmd.append(version)
+helpers.run_cmd(cmd)
+
+print("\n* Creating DB")
+helpers.run_cmd(['codeql', 'database', 'create', dbDir, '--language=csharp',
+ '--command', 'dotnet build /t:rebuild ' + projectDirIn])
+
+if not os.path.isdir(dbDir):
+ print("Expected database directory " + dbDir + " not found.")
+ exit(1)
+
+print("\n* Running stubbing CodeQL query")
+helpers.run_cmd(['codeql', 'query', 'run', os.path.join(
+ thisDir, 'AllStubsFromReference.ql'), '--database', dbDir, '--output', bqrsFile])
+
+helpers.run_cmd(['codeql', 'bqrs', 'decode', bqrsFile, '--output',
+ jsonFile, '--format=json'])
+
+print("\n* Creating new raw output project")
+rawSrcOutputDirName = 'src'
+rawSrcOutputDir = os.path.join(rawOutputDir, rawSrcOutputDirName)
+helpers.run_cmd(['dotnet', 'new', 'classlib', "--language", "C#",
+ '--name', rawSrcOutputDirName, '--output', rawSrcOutputDir])
+helpers.remove_files(rawSrcOutputDir, '.cs')
+
+# load json from query result file and split it into separate .cs files
+pathInfos = {}
+with open(jsonFile) as json_data:
+ data = json.load(json_data)
+ for row in data['#select']['tuples']:
+ pathInfos[row[3]] = os.path.join(rawSrcOutputDir, row[1] + '.cs')
+ with open(pathInfos[row[3]], 'a') as f:
+ f.write(row[4])
+
+print("\n --> Generated stub files: " + rawSrcOutputDir)
+
+print("\n* Formatting files")
+helpers.run_cmd(['dotnet', 'format', rawSrcOutputDir])
+
+print("\n --> Generated (formatted) stub files: " + rawSrcOutputDir)
+
+print("\n* Processing project.assets.json to generate folder structure")
+stubsDirName = 'stubs'
+stubsDir = os.path.join(outputDir, stubsDirName)
+os.makedirs(stubsDir)
+
+frameworksDirName = '_frameworks'
+frameworksDir = os.path.join(stubsDir, frameworksDirName)
+
+frameworks = set()
+copiedFiles = set()
+
+assetsJsonFile = os.path.join(projectDirIn, 'obj', 'project.assets.json')
+with open(assetsJsonFile) as json_data:
+ data = json.load(json_data)
+ if len(data['targets']) > 1:
+ print("ERROR: More than one target found in " + assetsJsonFile)
+ exit(1)
+ target = list(data['targets'].keys())[0]
+ print("Found target: " + target)
+ for package in data['targets'][target].keys():
+ parts = package.split('/')
+ name = parts[0]
+ version = parts[1]
+ packageDir = os.path.join(stubsDir, name, version)
+ if not os.path.exists(packageDir):
+ os.makedirs(packageDir)
+ print(' * Processing package: ' + name + '/' + version)
+ with open(os.path.join(packageDir, name + '.csproj'), 'a') as pf:
+
+ write_csproj_prefix(pf)
+ pf.write(' \n')
+
+ dlls = set()
+ if 'compile' in data['targets'][target][package]:
+ for dll in data['targets'][target][package]['compile']:
+ dlls.add(
+ (name + '/' + version + '/' + dll).lower())
+ if 'runtime' in data['targets'][target][package]:
+ for dll in data['targets'][target][package]['runtime']:
+ dlls.add((name + '/' + version + '/' + dll).lower())
+
+ for pathInfo in pathInfos:
+ for dll in dlls:
+ if pathInfo.lower().endswith(dll):
+ copiedFiles.add(pathInfo)
+ shutil.copy2(pathInfos[pathInfo], packageDir)
+
+ if 'dependencies' in data['targets'][target][package]:
+ for dependency in data['targets'][target][package]['dependencies'].keys():
+ depVersion = data['targets'][target][package]['dependencies'][dependency]
+ pf.write(' \n')
+
+ if 'frameworkReferences' in data['targets'][target][package]:
+ if not os.path.exists(frameworksDir):
+ os.makedirs(frameworksDir)
+ for framework in data['targets'][target][package]['frameworkReferences']:
+ frameworks.add(framework)
+ frameworkDir = os.path.join(
+ frameworksDir, framework)
+ if not os.path.exists(frameworkDir):
+ os.makedirs(frameworkDir)
+ pf.write(' \n')
+
+ pf.write(' \n')
+
+ pf.write(' \n')
+ pf.write(' \n')
+
+# Processing references frameworks
+for framework in frameworks:
+ with open(os.path.join(frameworksDir, framework, framework + '.csproj'), 'a') as pf:
+
+ write_csproj_prefix(pf)
+ pf.write(' \n')
+ pf.write(
+ ' \n')
+ pf.write(' \n')
+ pf.write('\n')
+
+ for pathInfo in pathInfos:
+ if 'packs/' + framework.lower() in pathInfo.lower():
+ copiedFiles.add(pathInfo)
+ shutil.copy2(pathInfos[pathInfo], os.path.join(
+ frameworksDir, framework))
+
+# Processing assemblies in Microsoft.NETCore.App.Ref
+frameworkDir = os.path.join(frameworksDir, 'Microsoft.NETCore.App')
+if not os.path.exists(frameworkDir):
+ os.makedirs(frameworkDir)
+with open(os.path.join(frameworksDir, 'Microsoft.NETCore.App', 'Microsoft.NETCore.App.csproj'), 'a') as pf:
+ write_csproj_prefix(pf)
+ pf.write('\n')
+
+ for pathInfo in pathInfos:
+ if 'packs/microsoft.netcore.app.ref/' in pathInfo.lower():
+ copiedFiles.add(pathInfo)
+ shutil.copy2(pathInfos[pathInfo], frameworkDir)
+
+for pathInfo in pathInfos:
+ if pathInfo not in copiedFiles:
+ print('Not copied to nuget or framework folder: ' + pathInfo)
+ othersDir = os.path.join(stubsDir, 'others')
+ if not os.path.exists(othersDir):
+ os.makedirs(othersDir)
+ shutil.copy2(pathInfos[pathInfo], othersDir)
+
+print("\n --> Generated structured stub files: " + stubsDir)
+
+exit(0)
diff --git a/csharp/ql/src/Useless code/DefaultToString.ql b/csharp/ql/src/Useless code/DefaultToString.ql
index 0c724ab1741..544347576fe 100644
--- a/csharp/ql/src/Useless code/DefaultToString.ql
+++ b/csharp/ql/src/Useless code/DefaultToString.ql
@@ -10,4 +10,4 @@
* maintainability
*/
-import DefaultToString
+import DefaultToStringQuery
diff --git a/csharp/ql/src/Useless code/DefaultToString.qll b/csharp/ql/src/Useless code/DefaultToStringQuery.qll
similarity index 100%
rename from csharp/ql/src/Useless code/DefaultToString.qll
rename to csharp/ql/src/Useless code/DefaultToStringQuery.qll
diff --git a/csharp/ql/src/meta/frameworks/Coverage.ql b/csharp/ql/src/meta/frameworks/Coverage.ql
new file mode 100644
index 00000000000..f24d519e51d
--- /dev/null
+++ b/csharp/ql/src/meta/frameworks/Coverage.ql
@@ -0,0 +1,14 @@
+/**
+ * @name Framework coverage
+ * @description The number of API endpoints covered by CSV models sorted by
+ * package and source-, sink-, and summary-kind.
+ * @kind table
+ * @id cs/meta/framework-coverage
+ */
+
+import csharp
+import semmle.code.csharp.dataflow.ExternalFlow
+
+from string namespace, int pkgs, string kind, string part, int n
+where modelCoverage(namespace, pkgs, kind, part, n)
+select namespace, pkgs, kind, part, n
diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll
index f37a4f2d074..884f4406d01 100644
--- a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll
+++ b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll
@@ -284,8 +284,7 @@ private module SsaDefReaches {
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
- rnk = ssaRefRank(bb, i, v, SsaRead()) and
- variableRead(bb, i, v, _)
+ rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll
index 8077245adb3..77f5249841f 100644
--- a/csharp/ql/src/semmle/code/csharp/Generics.qll
+++ b/csharp/ql/src/semmle/code/csharp/Generics.qll
@@ -185,6 +185,11 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
/** Gets the generic that defines this type parameter. */
UnboundGeneric getGeneric() { type_parameters(this, _, result, _) }
+ final override predicate hasQualifiedName(string qualifier, string name) {
+ qualifier = "" and
+ name = this.getName()
+ }
+
override string getAPrimaryQlClass() { result = "TypeParameter" }
}
diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll
index 191c7c85516..9f8408621fc 100644
--- a/csharp/ql/src/semmle/code/csharp/Member.qll
+++ b/csharp/ql/src/semmle/code/csharp/Member.qll
@@ -34,7 +34,12 @@ class Declaration extends DotNet::Declaration, Element, @declaration {
* ```
*/
string getQualifiedNameWithTypes() {
- result = this.getDeclaringType().getQualifiedName() + "." + this.toStringWithTypes()
+ exists(string qual |
+ qual = this.getDeclaringType().getQualifiedName() and
+ if this instanceof NestedType
+ then result = qual + "+" + this.toStringWithTypes()
+ else result = qual + "." + this.toStringWithTypes()
+ )
}
/**
@@ -326,6 +331,7 @@ class Virtualizable extends Member, @virtualizable {
* (An example where `getOverridee*().getImplementee()` would be incorrect.)
* - If this member is `D.M` then `I.M = getAnUltimateImplementee()`.
*/
+ pragma[nomagic]
Virtualizable getAnUltimateImplementee() {
exists(Virtualizable implementation, ValueOrRefType implementationType |
implements(implementation, result, implementationType)
diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll
index cf055062e33..eea631ba377 100644
--- a/csharp/ql/src/semmle/code/csharp/Type.qll
+++ b/csharp/ql/src/semmle/code/csharp/Type.qll
@@ -55,6 +55,28 @@ private predicate isObjectClass(Class c) { c instanceof ObjectType }
* Either a value type (`ValueType`) or a reference type (`RefType`).
*/
class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_or_ref_type {
+ /** Gets the name of this type without `<...>` brackets, in case it is a constructed type. */
+ private string getNameWithoutBrackets() {
+ exists(UnboundGenericType unbound, string name |
+ unbound = this.(ConstructedType).getUnboundDeclaration() and
+ name = unbound.getName() and
+ result = name.prefix(name.length() - unbound.getNumberOfTypeParameters() - 1)
+ )
+ or
+ not this instanceof ConstructedType and
+ result = this.getName()
+ }
+
+ language[monotonicAggregates]
+ private string getQualifiedTypeArguments() {
+ result =
+ strictconcat(Type t, int i |
+ t = this.(ConstructedType).getTypeArgument(i)
+ |
+ t.getQualifiedName(), "," order by i
+ )
+ }
+
/**
* Holds if this type has the qualified name `qualifier`.`name`.
*
@@ -62,10 +84,21 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* `qualifier`=`System.IO` and `name`=`IOException`.
*/
override predicate hasQualifiedName(string qualifier, string name) {
- name = this.getName() and
- if exists(this.getDeclaringType())
- then qualifier = this.getDeclaringType().getQualifiedName()
- else qualifier = this.getNamespace().getQualifiedName()
+ exists(string name0 |
+ not this instanceof ConstructedType and
+ name = name0
+ or
+ name = name0 + "<" + this.getQualifiedTypeArguments() + ">"
+ |
+ exists(string enclosing |
+ this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
+ name0 = enclosing + "+" + this.getNameWithoutBrackets()
+ )
+ or
+ not exists(this.getDeclaringType()) and
+ qualifier = this.getNamespace().getQualifiedName() and
+ name0 = this.getNameWithoutBrackets()
+ )
}
/** Gets the namespace containing this type. */
@@ -994,6 +1027,13 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type {
not type_location(this, _) and
result = this.getElementType().getALocation()
}
+
+ final override predicate hasQualifiedName(string qualifier, string name) {
+ exists(Type elementType, string name0 |
+ elementType.hasQualifiedName(qualifier, name0) and
+ name = name0 + this.getDimensionString(elementType)
+ )
+ }
}
/**
@@ -1013,6 +1053,13 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type {
override string toString() { result = DotNet::PointerType.super.toString() }
override string getAPrimaryQlClass() { result = "PointerType" }
+
+ final override predicate hasQualifiedName(string qualifier, string name) {
+ exists(string name0 |
+ this.getReferentType().hasQualifiedName(qualifier, name0) and
+ name = name0 + "*"
+ )
+ }
}
/**
@@ -1083,6 +1130,10 @@ class TupleType extends ValueType, @tuple_type {
override string getLabel() { result = getUnderlyingType().getLabel() }
override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) }
+
+ final override predicate hasQualifiedName(string qualifier, string name) {
+ this.getUnderlyingType().hasQualifiedName(qualifier, name)
+ }
}
/**
diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll
index aa9c9993b3d..73f739a1f7b 100644
--- a/csharp/ql/src/semmle/code/csharp/Unification.qll
+++ b/csharp/ql/src/semmle/code/csharp/Unification.qll
@@ -485,6 +485,7 @@ module Gvn {
/**
* Gets the leaf GVN inside GVN `t`, by following the path `path`, if any.
*/
+ pragma[noinline]
private GvnType getLeafTypeAt(GvnType t, TTypePath path) {
result = getTypeAt(t, path) and
not result instanceof ConstructedGvnType
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll
index f37a4f2d074..884f4406d01 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll
@@ -284,8 +284,7 @@ private module SsaDefReaches {
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
- rnk = ssaRefRank(bb, i, v, SsaRead()) and
- variableRead(bb, i, v, _)
+ rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/ExternalFlow.qll
new file mode 100644
index 00000000000..bec5d5a4162
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/ExternalFlow.qll
@@ -0,0 +1,442 @@
+/**
+ * INTERNAL use only. This is an experimental API subject to change without notice.
+ *
+ * Provides classes and predicates for dealing with flow models specified in CSV format.
+ *
+ * The CSV specification has the following columns:
+ * - Sources:
+ * `namespace; type; subtypes; name; signature; ext; output; kind`
+ * - Sinks:
+ * `namespace; type; subtypes; name; signature; ext; input; kind`
+ * - Summaries:
+ * `namespace; type; subtypes; name; signature; ext; input; output; kind`
+ *
+ * The interpretation of a row is similar to API-graphs with a left-to-right
+ * reading.
+ * 1. The `namespace` column selects a namespace.
+ * 2. The `type` column selects a type within that namespace.
+ * 3. The `subtypes` is a boolean that indicates whether to jump to an
+ * arbitrary subtype of that type.
+ * 4. The `name` column optionally selects a specific named member of the type.
+ * 5. The `signature` column optionally restricts the named member. If
+ * `signature` is blank then no such filtering is done. The format of the
+ * signature is a comma-separated list of types enclosed in parentheses. The
+ * types can be short names or fully qualified names (mixing these two options
+ * is not allowed within a single signature).
+ * 6. The `ext` column specifies additional API-graph-like edges. Currently
+ * there are only two valid values: "" and "Attribute". The empty string has no
+ * effect. "Attribute" applies if `name` and `signature` were left blank and
+ * acts by selecting an element that is attributed with the attribute type
+ * selected by the first 4 columns. This can be another member such as a field,
+ * property, method, or parameter.
+ * 7. The `input` column specifies how data enters the element selected by the
+ * first 6 columns, and the `output` column specifies how data leaves the
+ * element selected by the first 6 columns. For sinks, an `input` can be either "",
+ * "Argument[n]", "Argument[n1..n2]", or "ReturnValue":
+ * - "": Selects a write to the selected element in case this is a field or property.
+ * - "Argument[n]": Selects an argument in a call to the selected element.
+ * The arguments are zero-indexed, and `-1` specifies the qualifier.
+ * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in
+ * the given range. The range is inclusive at both ends.
+ * - "ReturnValue": Selects a value being returned by the selected element.
+ * This requires that the selected element is a method with a body.
+ *
+ * For sources, an `output` can be either "", "Argument[n]", "Argument[n1..n2]",
+ * "Parameter", "Parameter[n]", "Parameter[n1..n2]", or "ReturnValue":
+ * - "": Selects a read of a selected field, property, or parameter.
+ * - "Argument[n]": Selects the post-update value of an argument in a call to the
+ * selected element. That is, the value of the argument after the call returns.
+ * The arguments are zero-indexed, and `-1` specifies the qualifier.
+ * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in
+ * the given range. The range is inclusive at both ends.
+ * - "Parameter": Selects the value of a parameter of the selected element.
+ * "Parameter" is also allowed in case the selected element is already a
+ * parameter itself.
+ * - "Parameter[n]": Similar to "Parameter" but restricted to a specific
+ * numbered parameter (zero-indexed, and `-1` specifies the value of `this`).
+ * - "Parameter[n1..n2]": Similar to "Parameter[n]" but selects any parameter
+ * in the given range. The range is inclusive at both ends.
+ * - "ReturnValue": Selects the return value of a call to the selected element.
+ *
+ * For summaries, `input` and `output` may be prefixed by one of the following,
+ * separated by the "of" keyword:
+ * - "Element": Selects an element in a collection.
+ * - "Field[f]": Selects the contents of field `f`.
+ * - "Property[p]": Selects the contents of property `p`.
+ *
+ * 8. The `kind` column is a tag that can be referenced from QL to determine to
+ * which classes the interpreted elements should be added. For example, for
+ * sources "remote" indicates a default remote flow source, and for summaries
+ * "taint" indicates a default additional taint step and "value" indicates a
+ * globally applicable value-preserving step.
+ */
+
+import csharp
+private import internal.DataFlowDispatch
+private import internal.DataFlowPrivate
+private import internal.DataFlowPublic
+private import internal.FlowSummaryImpl::Public
+private import internal.FlowSummaryImpl::Private::External
+private import internal.FlowSummaryImplSpecific
+
+/**
+ * A module importing the frameworks that provide external flow data,
+ * ensuring that they are visible to the taint tracking / data flow library.
+ */
+private module Frameworks {
+ private import semmle.code.csharp.security.dataflow.flowsources.Local
+ private import semmle.code.csharp.security.dataflow.flowsinks.Html
+ private import semmle.code.csharp.frameworks.System
+ private import semmle.code.csharp.security.dataflow.XSSSinks
+}
+
+/**
+ * A unit class for adding additional source model rows.
+ *
+ * Extend this class to add additional source definitions.
+ */
+class SourceModelCsv extends Unit {
+ /** Holds if `row` specifies a source definition. */
+ abstract predicate row(string row);
+}
+
+/**
+ * A unit class for adding additional sink model rows.
+ *
+ * Extend this class to add additional sink definitions.
+ */
+class SinkModelCsv extends Unit {
+ /** Holds if `row` specifies a sink definition. */
+ abstract predicate row(string row);
+}
+
+/**
+ * A unit class for adding additional summary model rows.
+ *
+ * Extend this class to add additional flow summary definitions.
+ */
+class SummaryModelCsv extends Unit {
+ /** Holds if `row` specifies a summary definition. */
+ abstract predicate row(string row);
+}
+
+private predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
+
+private predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
+
+private predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
+
+/** Holds if a source model exists for the given parameters. */
+predicate sourceModel(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext,
+ string output, string kind
+) {
+ exists(string row |
+ sourceModel(row) and
+ row.splitAt(";", 0) = namespace and
+ row.splitAt(";", 1) = type and
+ row.splitAt(";", 2) = subtypes.toString() and
+ subtypes = [true, false] and
+ row.splitAt(";", 3) = name and
+ row.splitAt(";", 4) = signature and
+ row.splitAt(";", 5) = ext and
+ row.splitAt(";", 6) = output and
+ row.splitAt(";", 7) = kind
+ )
+}
+
+/** Holds if a sink model exists for the given parameters. */
+predicate sinkModel(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext,
+ string input, string kind
+) {
+ exists(string row |
+ sinkModel(row) and
+ row.splitAt(";", 0) = namespace and
+ row.splitAt(";", 1) = type and
+ row.splitAt(";", 2) = subtypes.toString() and
+ subtypes = [true, false] and
+ row.splitAt(";", 3) = name and
+ row.splitAt(";", 4) = signature and
+ row.splitAt(";", 5) = ext and
+ row.splitAt(";", 6) = input and
+ row.splitAt(";", 7) = kind
+ )
+}
+
+/** Holds if a summary model exists for the given parameters. */
+predicate summaryModel(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext,
+ string input, string output, string kind
+) {
+ exists(string row |
+ summaryModel(row) and
+ row.splitAt(";", 0) = namespace and
+ row.splitAt(";", 1) = type and
+ row.splitAt(";", 2) = subtypes.toString() and
+ subtypes = [true, false] and
+ row.splitAt(";", 3) = name and
+ row.splitAt(";", 4) = signature and
+ row.splitAt(";", 5) = ext and
+ row.splitAt(";", 6) = input and
+ row.splitAt(";", 7) = output and
+ row.splitAt(";", 8) = kind
+ )
+}
+
+private predicate relevantNamespace(string namespace) {
+ sourceModel(namespace, _, _, _, _, _, _, _) or
+ sinkModel(namespace, _, _, _, _, _, _, _) or
+ summaryModel(namespace, _, _, _, _, _, _, _, _)
+}
+
+private predicate namespaceLink(string shortns, string longns) {
+ relevantNamespace(shortns) and
+ relevantNamespace(longns) and
+ longns.prefix(longns.indexOf(".")) = shortns
+}
+
+private predicate canonicalNamespace(string namespace) {
+ relevantNamespace(namespace) and not namespaceLink(_, namespace)
+}
+
+private predicate canonicalNamespaceLink(string namespace, string subns) {
+ canonicalNamespace(namespace) and
+ (subns = namespace or namespaceLink(namespace, subns))
+}
+
+/**
+ * Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
+ * kind `(kind, part)`.
+ */
+predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
+ namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
+ (
+ part = "source" and
+ n =
+ strictcount(string subns, string type, boolean subtypes, string name, string signature,
+ string ext, string output |
+ canonicalNamespaceLink(namespace, subns) and
+ sourceModel(subns, type, subtypes, name, signature, ext, output, kind)
+ )
+ or
+ part = "sink" and
+ n =
+ strictcount(string subns, string type, boolean subtypes, string name, string signature,
+ string ext, string input |
+ canonicalNamespaceLink(namespace, subns) and
+ sinkModel(subns, type, subtypes, name, signature, ext, input, kind)
+ )
+ or
+ part = "summary" and
+ n =
+ strictcount(string subns, string type, boolean subtypes, string name, string signature,
+ string ext, string input, string output |
+ canonicalNamespaceLink(namespace, subns) and
+ summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind)
+ )
+ )
+}
+
+/** Provides a query predicate to check the CSV data for validation errors. */
+module CsvValidation {
+ /** Holds if some row in a CSV-based flow model appears to contain typos. */
+ query predicate invalidModelRow(string msg) {
+ exists(string pred, string namespace, string type, string name, string signature, string ext |
+ sourceModel(namespace, type, _, name, signature, ext, _, _) and pred = "source"
+ or
+ sinkModel(namespace, type, _, name, signature, ext, _, _) and pred = "sink"
+ or
+ summaryModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "summary"
+ |
+ not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
+ msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
+ or
+ not type.regexpMatch("[a-zA-Z0-9_<>\\.\\+]+") and
+ msg = "Dubious type \"" + type + "\" in " + pred + " model."
+ or
+ not name.regexpMatch("[a-zA-Z0-9_]*") and
+ msg = "Dubious name \"" + name + "\" in " + pred + " model."
+ or
+ not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+,\\[\\]]*\\)") and
+ msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
+ or
+ not ext.regexpMatch("|Attribute") and
+ msg = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
+ )
+ or
+ exists(string pred, string input, string part |
+ sinkModel(_, _, _, _, _, _, input, _) and pred = "sink"
+ or
+ summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
+ |
+ (
+ invalidSpecComponent(input, part) and
+ not part = "" and
+ not (part = "Argument" and pred = "sink") and
+ not parseArg(part, _)
+ or
+ specSplit(input, part, _) and
+ parseParam(part, _)
+ ) and
+ msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
+ )
+ or
+ exists(string pred, string output, string part |
+ sourceModel(_, _, _, _, _, _, output, _) and pred = "source"
+ or
+ summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
+ |
+ invalidSpecComponent(output, part) and
+ not part = "" and
+ not (part = ["Argument", "Parameter"] and pred = "source") and
+ msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
+ )
+ or
+ exists(string pred, string row, int expect |
+ sourceModel(row) and expect = 8 and pred = "source"
+ or
+ sinkModel(row) and expect = 8 and pred = "sink"
+ or
+ summaryModel(row) and expect = 9 and pred = "summary"
+ |
+ exists(int cols |
+ cols = 1 + max(int n | exists(row.splitAt(";", n))) and
+ cols != expect and
+ msg =
+ "Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
+ "."
+ )
+ or
+ exists(string b |
+ b = row.splitAt(";", 2) and
+ not b = ["true", "false"] and
+ msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
+ )
+ )
+ }
+}
+
+private predicate elementSpec(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
+) {
+ sourceModel(namespace, type, subtypes, name, signature, ext, _, _) or
+ sinkModel(namespace, type, subtypes, name, signature, ext, _, _) or
+ summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _)
+}
+
+private class UnboundValueOrRefType extends ValueOrRefType {
+ UnboundValueOrRefType() { this.isUnboundDeclaration() }
+
+ UnboundValueOrRefType getASubTypeUnbound() { result = this.getASubType().getUnboundDeclaration() }
+}
+
+bindingset[namespace, type, subtypes]
+private UnboundValueOrRefType interpretType(string namespace, string type, boolean subtypes) {
+ exists(UnboundValueOrRefType t |
+ t.hasQualifiedName(namespace, type) and
+ if subtypes = true then result = t.getASubTypeUnbound*() else result = t
+ )
+}
+
+private Member interpretMember(
+ string namespace, string type, boolean subtypes, string name, string signature
+) {
+ elementSpec(namespace, type, subtypes, name, signature, _) and
+ exists(UnboundValueOrRefType t |
+ t = interpretType(namespace, type, subtypes) and
+ result.getDeclaringType() = t and
+ result.hasName(name)
+ )
+}
+
+private class InterpretedCallable extends Callable {
+ InterpretedCallable() { this = interpretMember(_, _, _, _, _) }
+}
+
+private string paramsStringPartA(InterpretedCallable c, int i) {
+ i = -1 and result = "("
+ or
+ exists(int n |
+ exists(c.getParameter(n)) and
+ i = 2 * n - 1 and
+ result = "," and
+ n != 0
+ )
+ or
+ i = 2 * c.getNumberOfParameters() and result = ")"
+}
+
+private string paramsStringPartB(InterpretedCallable c, int i) {
+ exists(int n, string p, Type t |
+ t = c.getParameter(n).getType() and
+ i = 2 * n and
+ result = p and
+ p = t.getQualifiedName()
+ )
+}
+
+private string paramsString(InterpretedCallable c) {
+ result =
+ strictconcat(int i, string s |
+ s in [paramsStringPartA(c, i), paramsStringPartB(c, i)]
+ |
+ s order by i
+ )
+}
+
+private Element interpretElement0(
+ string namespace, string type, boolean subtypes, string name, string signature
+) {
+ elementSpec(namespace, type, subtypes, name, signature, _) and
+ exists(UnboundValueOrRefType t | t = interpretType(namespace, type, subtypes) |
+ exists(Member m |
+ result = m and
+ m.getDeclaringType() = t and
+ m.hasName(name)
+ |
+ signature = ""
+ or
+ paramsString(m) = signature
+ )
+ or
+ result = t and
+ name = "" and
+ signature = ""
+ )
+}
+
+/** Gets the source/sink/summary element corresponding to the supplied parameters. */
+Element interpretElement(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
+) {
+ elementSpec(namespace, type, subtypes, name, signature, ext) and
+ exists(Element e | e = interpretElement0(namespace, type, subtypes, name, signature) |
+ ext = "" and result = e
+ or
+ ext = "Attribute" and result.(Attributable).getAnAttribute().getType() = e
+ )
+}
+
+cached
+private module Cached {
+ /**
+ * Holds if `node` is specified as a source with the given kind in a CSV flow
+ * model.
+ */
+ cached
+ predicate sourceNode(Node node, string kind) {
+ exists(InterpretNode n | isSourceNode(n, kind) and n.asNode() = node)
+ }
+
+ /**
+ * Holds if `node` is specified as a sink with the given kind in a CSV flow
+ * model.
+ */
+ cached
+ predicate sinkNode(Node node, string kind) {
+ exists(InterpretNode n | isSinkNode(n, kind) and n.asNode() = node)
+ }
+}
+
+import Cached
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll
index 374c42ed7e9..a20c3876050 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll
@@ -35,22 +35,6 @@ module SummaryComponent {
/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = return(any(NormalReturnKind rk)) }
- /**
- * Gets a summary component that represents the return value through the `i`th
- * `out` argument of a call.
- */
- SummaryComponent outArgument(int i) {
- result = return(any(OutReturnKind rk | rk.getPosition() = i))
- }
-
- /**
- * Gets a summary component that represents the return value through the `i`th
- * `ref` argument of a call.
- */
- SummaryComponent refArgument(int i) {
- result = return(any(RefReturnKind rk | rk.getPosition() = i))
- }
-
/** Gets a summary component that represents a jump to `c`. */
SummaryComponent jump(Callable c) {
result =
@@ -88,18 +72,6 @@ module SummaryComponentStack {
/** Gets a singleton stack representing the return value of a call. */
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
- /**
- * Gets a singleton stack representing the return value through the `i`th
- * `out` argument of a call.
- */
- SummaryComponentStack outArgument(int i) { result = singleton(SummaryComponent::outArgument(i)) }
-
- /**
- * Gets a singleton stack representing the return value through the `i`th
- * `ref` argument of a call.
- */
- SummaryComponentStack refArgument(int i) { result = singleton(SummaryComponent::refArgument(i)) }
-
/** Gets a singleton stack representing a jump to `c`. */
SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) }
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
index a7c6869a4cc..8b76184a321 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
@@ -383,7 +383,7 @@ private module FrameworkDataFlowAdaptor {
or
exists(int i |
result = TCallableFlowSinkArg(i) and
- output = SummaryComponentStack::outArgument(i)
+ output = SummaryComponentStack::argument(i)
)
or
exists(int i, int j | result = TCallableFlowSinkDelegateArg(i, j) |
@@ -499,33 +499,6 @@ private module FrameworkDataFlowAdaptor {
}
}
-/** Data flow for `System.Int32`. */
-class SystemInt32Flow extends LibraryTypeDataFlow, SystemInt32Struct {
- override predicate callableFlow(
- CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
- boolean preservesValue
- ) {
- methodFlow(source, sink, c) and
- preservesValue = false
- }
-
- private predicate methodFlow(
- CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m
- ) {
- m = getParseMethod() and
- source = TCallableFlowSourceArg(0) and
- sink = TCallableFlowSinkReturn()
- or
- m = getTryParseMethod() and
- source = TCallableFlowSourceArg(0) and
- (
- sink = TCallableFlowSinkReturn()
- or
- sink = TCallableFlowSinkArg(any(int i | m.getParameter(i).isOutOrRef()))
- )
- }
-}
-
/** Data flow for `System.Boolean`. */
class SystemBooleanFlow extends LibraryTypeDataFlow, SystemBooleanStruct {
override predicate callableFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
index 04465f5ae9e..0f233d7e92d 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
@@ -6,6 +6,7 @@ private import DataFlowPublic
private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.FlowSummary
+private import semmle.code.csharp.dataflow.ExternalFlow
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.frameworks.system.Collections
private import semmle.code.csharp.frameworks.system.collections.Generic
@@ -14,6 +15,8 @@ private predicate summarizedCallable(DataFlowCallable c) {
c instanceof SummarizedCallable
or
FlowSummaryImpl::Private::summaryReturnNode(_, TJumpReturnKind(c, _))
+ or
+ c = interpretElement(_, _, _, _, _, _)
}
/**
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
index 9b14db7ef88..5c2dbb30084 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
@@ -81,6 +81,12 @@ abstract class Configuration extends string {
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
+ /**
+ * Holds if an arbitrary number of implicit read steps of content `c` may be
+ * taken at `node`.
+ */
+ predicate allowImplicitRead(Node node, Content c) { none() }
+
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
@@ -182,75 +188,210 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
-private predicate inBarrier(Node node, Configuration config) {
- config.isBarrierIn(node) and
- config.isSource(node)
+private newtype TNodeEx =
+ TNodeNormal(Node n) or
+ TNodeImplicitRead(Node n, boolean hasRead) {
+ any(Configuration c).allowImplicitRead(n, _) and hasRead = [false, true]
+ }
+
+private class NodeEx extends TNodeEx {
+ string toString() {
+ result = this.asNode().toString()
+ or
+ exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
+ }
+
+ Node asNode() { this = TNodeNormal(result) }
+
+ predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
+
+ Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
+
+ pragma[nomagic]
+ private DataFlowCallable getEnclosingCallable0() {
+ nodeEnclosingCallable(this.projectToNode(), result)
+ }
+
+ pragma[inline]
+ DataFlowCallable getEnclosingCallable() {
+ pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
+ }
+
+ pragma[nomagic]
+ private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
+
+ pragma[inline]
+ DataFlowType getDataFlowType() {
+ pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.projectToNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
}
-private predicate outBarrier(Node node, Configuration config) {
- config.isBarrierOut(node) and
- config.isSink(node)
+private class ArgNodeEx extends NodeEx {
+ ArgNodeEx() { this.asNode() instanceof ArgNode }
}
-private predicate fullBarrier(Node node, Configuration config) {
- config.isBarrier(node)
- or
- config.isBarrierIn(node) and
- not config.isSource(node)
- or
- config.isBarrierOut(node) and
- not config.isSink(node)
- or
- exists(BarrierGuard g |
- config.isBarrierGuard(g) and
- node = g.getAGuardedNode()
+private class ParamNodeEx extends NodeEx {
+ ParamNodeEx() { this.asNode() instanceof ParamNode }
+
+ predicate isParameterOf(DataFlowCallable c, int i) {
+ this.asNode().(ParamNode).isParameterOf(c, i)
+ }
+
+ int getPosition() { this.isParameterOf(_, result) }
+}
+
+private class RetNodeEx extends NodeEx {
+ RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
+
+ ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
+
+ ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
+}
+
+private predicate inBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierIn(n) and
+ config.isSource(n)
)
}
+private predicate outBarrier(NodeEx node, Configuration config) {
+ exists(Node n |
+ node.asNode() = n and
+ config.isBarrierOut(n) and
+ config.isSink(n)
+ )
+}
+
+private predicate fullBarrier(NodeEx node, Configuration config) {
+ exists(Node n | node.asNode() = n |
+ config.isBarrier(n)
+ or
+ config.isBarrierIn(n) and
+ not config.isSource(n)
+ or
+ config.isBarrierOut(n) and
+ not config.isSink(n)
+ or
+ exists(BarrierGuard g |
+ config.isBarrierGuard(g) and
+ n = g.getAGuardedNode()
+ )
+ )
+}
+
+pragma[nomagic]
+private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
+
+pragma[nomagic]
+private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
+
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
-private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- simpleLocalFlowStepExt(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ simpleLocalFlowStepExt(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.asNode() = n and
+ node2.isImplicitReadNode(n, false)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
-private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+ or
+ exists(Node n |
+ config.allowImplicitRead(n, _) and
+ node1.isImplicitReadNode(n, true) and
+ node2.asNode() = n
+ )
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
-private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStepCached(node1, node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ jumpStepCached(n1, n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
}
/**
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
-private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
- config.isAdditionalFlowStep(node1, node2) and
- getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
- not outBarrier(node1, config) and
- not inBarrier(node2, config) and
- not fullBarrier(node1, config) and
- not fullBarrier(node2, config)
+private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) {
+ exists(Node n1, Node n2 |
+ node1.asNode() = n1 and
+ node2.asNode() = n2 and
+ config.isAdditionalFlowStep(n1, n2) and
+ getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
+ not outBarrier(node1, config) and
+ not inBarrier(node2, config) and
+ not fullBarrier(node1, config) and
+ not fullBarrier(node2, config)
+ )
+}
+
+private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
+ read(node1.asNode(), c, node2.asNode())
+ or
+ exists(Node n |
+ node2.isImplicitReadNode(n, true) and
+ node1.isImplicitReadNode(n, _) and
+ config.allowImplicitRead(n, c)
+ )
+}
+
+private predicate store(
+ NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
+) {
+ store(node1.asNode(), tc, node2.asNode(), contentType) and
+ read(_, tc.getContent(), _, config)
+}
+
+pragma[nomagic]
+private predicate viableReturnPosOutEx(DataFlowCall call, ReturnPosition pos, NodeEx out) {
+ viableReturnPosOut(call, pos, out.asNode())
+}
+
+pragma[nomagic]
+private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx arg) {
+ viableParamArg(call, p.asNode(), arg.asNode())
}
/**
@@ -274,39 +415,39 @@ private module Stage1 {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
- predicate fwdFlow(Node node, Cc cc, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
- config.isSource(node) and
+ sourceNode(node, config) and
cc = false
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
- exists(Node mid |
+ exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
- store(mid, _, node, _) and
+ store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
@@ -318,9 +459,9 @@ private module Stage1 {
)
or
// flow into a callable
- exists(Node arg |
+ exists(NodeEx arg |
fwdFlow(arg, _, config) and
- viableParamArg(_, node, arg) and
+ viableParamArgEx(_, node, arg) and
cc = true
)
or
@@ -335,13 +476,13 @@ private module Stage1 {
)
}
- private predicate fwdFlow(Node node, Configuration config) { fwdFlow(node, _, config) }
+ private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
- private predicate fwdFlowRead(Content c, Node node, Cc cc, Configuration config) {
- exists(Node mid |
+ private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
+ exists(NodeEx mid |
fwdFlow(mid, cc, config) and
- read(mid, c, node)
+ read(mid, c, node, config)
)
}
@@ -350,33 +491,33 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node, TypedContent tc |
+ exists(NodeEx mid, NodeEx node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
- store(mid, tc, node, _) and
+ store(mid, tc, node, _, config) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
fwdFlow(ret, cc, config) and
- getReturnPosition(ret) = pos
+ ret.getReturnPosition() = pos
)
}
pragma[nomagic]
- private predicate fwdFlowOut(DataFlowCall call, Node out, Cc cc, Configuration config) {
+ private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
)
}
pragma[nomagic]
- private predicate fwdFlowOutFromArg(DataFlowCall call, Node out, Configuration config) {
+ private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) {
fwdFlowOut(call, out, true, config)
}
@@ -385,9 +526,9 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgNode arg |
+ exists(ArgNodeEx arg |
fwdFlow(arg, cc, config) and
- viableParamArg(call, _, arg)
+ viableParamArgEx(call, _, arg)
)
}
@@ -399,34 +540,34 @@ private module Stage1 {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}
pragma[nomagic]
- private predicate revFlow0(Node node, boolean toReturn, Configuration config) {
+ private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalLocalFlowStep(node, mid, config) and
revFlow(mid, toReturn, config)
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
)
or
- exists(Node mid |
+ exists(NodeEx mid |
additionalJumpStep(node, mid, config) and
revFlow(mid, _, config) and
toReturn = false
@@ -439,8 +580,8 @@ private module Stage1 {
)
or
// read
- exists(Node mid, Content c |
- read(node, c, mid) and
+ exists(NodeEx mid, Content c |
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
@@ -457,7 +598,7 @@ private module Stage1 {
// flow out of a callable
exists(ReturnPosition pos |
revFlowOut(pos, config) and
- getReturnPosition(node) = pos and
+ node.(RetNodeEx).getReturnPosition() = pos and
toReturn = true
)
}
@@ -467,20 +608,20 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
- exists(Node mid, Node node |
+ exists(NodeEx mid, NodeEx node |
fwdFlow(node, pragma[only_bind_into](config)) and
- read(node, c, mid) and
+ read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
- private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
- exists(Node mid, TypedContent tc |
+ private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
+ exists(NodeEx mid, TypedContent tc |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
- store(node, tc, mid, _) and
+ store(node, tc, mid, _, config) and
c = tc.getContent()
)
}
@@ -496,15 +637,15 @@ private module Stage1 {
pragma[nomagic]
predicate viableReturnPosOutNodeCandFwd1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
fwdFlowReturnPosition(pos, _, config) and
- viableReturnPosOut(call, pos, out)
+ viableReturnPosOutEx(call, pos, out)
}
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
- exists(DataFlowCall call, Node out |
+ exists(DataFlowCall call, NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
)
@@ -512,22 +653,24 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
- viableParamArg(call, p, arg) and
+ viableParamArgEx(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
- exists(ParamNode p |
+ private predicate revFlowIn(
+ DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
+ ) {
+ exists(ParamNodeEx p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNodeEx arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -538,7 +681,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) {
- exists(Node out |
+ exists(NodeEx out |
revFlow(out, toReturn, config) and
fwdFlowOutFromArg(call, out, config)
)
@@ -546,32 +689,33 @@ private module Stage1 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
exists(ap1)
)
}
pragma[nomagic]
- predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
+ predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
- read(n1, c, n2)
+ read(n1, c, n2, pragma[only_bind_into](config))
}
pragma[nomagic]
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow(node, toReturn, config) and exists(returnAp) and exists(ap)
}
- private predicate throughFlowNodeCand(Node node, Configuration config) {
+ private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
@@ -583,9 +727,9 @@ private module Stage1 {
private predicate returnFlowCallableNodeCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
- exists(ReturnNodeExt ret |
+ exists(RetNodeEx ret |
throughFlowNodeCand(ret, config) and
- callable = getNodeEnclosingCallable(ret) and
+ callable = ret.getEnclosingCallable() and
kind = ret.getKind()
)
}
@@ -594,22 +738,20 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
- getNodeEnclosingCallable(p) = c and
+ p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
- not exists(int pos |
- kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)
- )
+ not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(ArgNode arg, boolean toReturn |
+ exists(ArgNodeEx arg, boolean toReturn |
revFlow(arg, toReturn, config) and
revFlowInToReturn(call, arg, config) and
revFlowIsReturned(call, toReturn, config)
@@ -618,35 +760,35 @@ private module Stage1 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, config)) and
fields = count(Content f0 | fwdFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | fwdFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, config)) and
fields = count(Content f0 | revFlowConsCand(f0, config)) and
conscand = -1 and
- tuples = count(Node n, boolean b | revFlow(n, b, config))
+ tuples = count(NodeEx n, boolean b | revFlow(n, b, config))
}
/* End: Stage 1 logic. */
}
pragma[noinline]
-private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
localFlowStep(node1, node2, config)
}
pragma[noinline]
-private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
+private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) {
Stage1::revFlow(node2, config) and
additionalLocalFlowStep(node1, node2, config)
}
pragma[nomagic]
private predicate viableReturnPosOutNodeCand1(
- DataFlowCall call, ReturnPosition pos, Node out, Configuration config
+ DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
) {
Stage1::revFlow(out, config) and
Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config)
@@ -659,9 +801,9 @@ private predicate viableReturnPosOutNodeCand1(
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config
) {
- viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and
+ viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
@@ -669,7 +811,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
+ DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -681,7 +823,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -694,9 +836,9 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int branch(Node n1, Configuration conf) {
+private int branch(NodeEx n1, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
)
}
@@ -706,9 +848,9 @@ private int branch(Node n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call
* contexts.
*/
-private int join(Node n2, Configuration conf) {
+private int join(NodeEx n2, Configuration conf) {
result =
- strictcount(Node n |
+ strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
)
}
@@ -722,7 +864,7 @@ private int join(Node n2, Configuration conf) {
*/
pragma[nomagic]
private predicate flowOutOfCallNodeCand1(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, ret, out, config) and
exists(int b, int j |
@@ -741,7 +883,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -767,7 +909,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
- private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
+ private ApNil getApNil(NodeEx node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -801,19 +943,14 @@ private module Stage2 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
(
preservesValue = true and
@@ -834,17 +971,17 @@ private module Stage2 {
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 2 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -857,14 +994,14 @@ private module Stage2 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -875,7 +1012,7 @@ private module Stage2 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -883,7 +1020,7 @@ private module Stage2 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -924,7 +1061,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -948,7 +1085,7 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -957,13 +1094,13 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -971,17 +1108,16 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -989,9 +1125,9 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1008,7 +1144,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1016,21 +1152,23 @@ private module Stage2 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1041,7 +1179,7 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1058,41 +1196,41 @@ private module Stage2 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1108,7 +1246,7 @@ private module Stage2 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1132,7 +1270,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1146,7 +1284,7 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1155,10 +1293,10 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1167,8 +1305,10 @@ private module Stage2 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1178,9 +1318,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1197,7 +1337,7 @@ private module Stage2 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1206,16 +1346,17 @@ private module Stage2 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1224,7 +1365,7 @@ private module Stage2 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1236,20 +1377,21 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1257,7 +1399,7 @@ private module Stage2 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1266,23 +1408,23 @@ private module Stage2 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 2 logic. */
}
pragma[nomagic]
private predicate flowOutOfCallNodeCand2(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1291,7 +1433,8 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1303,10 +1446,10 @@ private module LocalFlowBigStep {
* A node where some checking is required, and hence the big-step relation
* is not allowed to step over.
*/
- private class FlowCheckNode extends Node {
+ private class FlowCheckNode extends NodeEx {
FlowCheckNode() {
- castNode(this) or
- clearsContentCached(this, _)
+ castNode(this.asNode()) or
+ clearsContentCached(this.asNode(), _)
}
}
@@ -1314,16 +1457,16 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- predicate localFlowEntry(Node node, Configuration config) {
+ predicate localFlowEntry(NodeEx node, Configuration config) {
Stage2::revFlow(node, config) and
(
- config.isSource(node) or
+ sourceNode(node, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParamNode or
- node instanceof OutNodeExt or
- store(_, _, node, _) or
- read(_, _, node) or
+ node instanceof ParamNodeEx or
+ node.asNode() instanceof OutNodeExt or
+ store(_, _, node, _, config) or
+ read(_, _, node, config) or
node instanceof FlowCheckNode
)
}
@@ -1332,23 +1475,25 @@ private module LocalFlowBigStep {
* Holds if `node` can be the last node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
- private predicate localFlowExit(Node node, Configuration config) {
- exists(Node next | Stage2::revFlow(next, config) |
+ private predicate localFlowExit(NodeEx node, Configuration config) {
+ exists(NodeEx next | Stage2::revFlow(next, config) |
jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
- store(node, _, next, _) or
- read(node, _, next)
+ store(node, _, next, _, config) or
+ read(node, _, next, config)
)
or
node instanceof FlowCheckNode
or
- config.isSink(node)
+ sinkNode(node, config)
}
pragma[noinline]
- private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
+ private predicate additionalLocalFlowStepNodeCand2(
+ NodeEx node1, NodeEx node2, Configuration config
+ ) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
@@ -1363,39 +1508,39 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
- Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
+ NodeEx node1, NodeEx node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeDataFlowType(node1)
+ t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeDataFlowType(node2)
+ t = node2.getDataFlowType()
) and
node1 != node2 and
- cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ cc.relevantFor(node1.getEnclosingCallable()) and
+ not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
- exists(Node mid |
+ exists(NodeEx mid |
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeDataFlowType(node2) and
+ t = node2.getDataFlowType() and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1407,8 +1552,8 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
predicate localFlowBigStep(
- Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config,
- LocalCallContext callContext
+ NodeEx node1, NodeEx node2, boolean preservesValue, AccessPathFrontNil apf,
+ Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, config)
@@ -1428,8 +1573,8 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -1464,19 +1609,14 @@ private module Stage3 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
-
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- any()
- }
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { any() }
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap, config, _) and exists(lcc)
}
@@ -1485,12 +1625,16 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
+ pragma[nomagic]
+ private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
+
+ pragma[nomagic]
+ private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
+
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) {
- not ap.isClearedAt(node) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
- else any()
+ private predicate filter(NodeEx node, Ap ap) {
+ not clear(node, ap) and
+ if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
bindingset[ap, contentType]
@@ -1501,7 +1645,7 @@ private module Stage3 {
}
/* Begin: Stage 3 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -1514,11 +1658,11 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -1531,21 +1675,21 @@ private module Stage3 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -1556,7 +1700,7 @@ private module Stage3 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -1564,7 +1708,7 @@ private module Stage3 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -1605,7 +1749,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -1629,7 +1773,7 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1638,13 +1782,13 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1652,17 +1796,16 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1670,9 +1813,9 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -1689,7 +1832,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1697,21 +1840,23 @@ private module Stage3 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -1722,7 +1867,7 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -1739,41 +1884,41 @@ private module Stage3 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -1789,7 +1934,7 @@ private module Stage3 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -1813,7 +1958,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -1827,7 +1972,7 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -1836,10 +1981,10 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -1848,8 +1993,10 @@ private module Stage3 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -1859,9 +2006,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1878,7 +2025,7 @@ private module Stage3 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -1887,16 +2034,17 @@ private module Stage3 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -1905,7 +2053,7 @@ private module Stage3 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -1917,20 +2065,21 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -1938,7 +2087,7 @@ private module Stage3 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -1947,16 +2096,16 @@ private module Stage3 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 3 logic. */
}
@@ -1965,7 +2114,7 @@ private module Stage3 {
* Holds if `argApf` is recorded as the summary context for flow reaching `node`
* and remains relevant for the following pruning stage.
*/
-private predicate flowCandSummaryCtx(Node node, AccessPathFront argApf, Configuration config) {
+private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
exists(AccessPathFront apf |
Stage3::revFlow(node, true, _, apf, config) and
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
@@ -1980,7 +2129,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
nodes =
- strictcount(Node n |
+ strictcount(NodeEx n |
Stage3::revFlow(n, _, _, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or
flowCandSummaryCtx(n, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
@@ -2175,8 +2324,8 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
- private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
+ private ApNil getApNil(NodeEx node) {
+ PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType())
}
bindingset[tc, tail]
@@ -2203,36 +2352,33 @@ private module Stage4 {
bindingset[call, c, outercc]
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
- c = resolveCall(call, outercc) and
+ checkCallContextCall(outercc, call, c) and
if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall()
}
- bindingset[call, c]
- private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
+ bindingset[call, c, innercc]
+ private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
+ checkCallContextReturn(innercc, c, call) and
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
}
- bindingset[innercc, inner, call]
- private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
- resolveReturn(innercc, inner, call)
- }
-
bindingset[node, cc, config]
- private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
+ private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
- result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
+ result =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ node.getEnclosingCallable())
}
private predicate localStep(
- Node node1, Node node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
+ NodeEx node1, NodeEx node2, boolean preservesValue, ApNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, node2, preservesValue, ap.getFront(), config, lcc)
}
pragma[nomagic]
private predicate flowOutOfCall(
- DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2241,7 +2387,8 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
+ Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2249,14 +2396,14 @@ private module Stage4 {
}
bindingset[node, ap]
- private predicate filter(Node node, Ap ap) { any() }
+ private predicate filter(NodeEx node, Ap ap) { any() }
// Type checking is not necessary here as it has already been done in stage 3.
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
/* Begin: Stage 4 logic. */
- private predicate flowCand(Node node, ApApprox apa, Configuration config) {
+ private predicate flowCand(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlow(node, _, _, apa, config)
}
@@ -2269,11 +2416,11 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
- DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
- PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(ret), _,
+ PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
}
@@ -2286,21 +2433,21 @@ private module Stage4 {
* argument.
*/
pragma[nomagic]
- predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
- private predicate fwdFlow0(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
+ private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
- exists(Node mid, Ap ap0, LocalCc localCc |
+ exists(NodeEx mid, Ap ap0, LocalCc localCc |
fwdFlow(mid, cc, argAp, ap0, config) and
localCc = getLocalCc(mid, cc, config)
|
@@ -2311,7 +2458,7 @@ private module Stage4 {
ap0 instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
@@ -2319,7 +2466,7 @@ private module Stage4 {
argAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
@@ -2360,7 +2507,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowStore(
- Node node1, Ap ap1, TypedContent tc, Node node2, Cc cc, ApOption argAp, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
@@ -2384,7 +2531,7 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowRead(
- Ap ap, Content c, Node node1, Node node2, Cc cc, ApOption argAp, Configuration config
+ Ap ap, Content c, NodeEx node1, NodeEx node2, Cc cc, ApOption argAp, Configuration config
) {
fwdFlow(node1, cc, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -2393,13 +2540,13 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNodeEx p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgNode arg, boolean allowsFieldFlow |
+ exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
- innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
+ innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2407,17 +2554,16 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutNotFromArg(
- Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
+ NodeEx out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(
- DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
+ DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
- inner = getNodeEnclosingCallable(ret) and
- checkCallContextReturn(innercc, inner, call) and
- ccOut = getCallContextReturn(inner, call)
+ inner = ret.getEnclosingCallable() and
+ ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2425,9 +2571,9 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowOutFromArg(
- DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
+ DataFlowCall call, NodeEx out, Ap argAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
+ exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
@@ -2444,7 +2590,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2452,21 +2598,23 @@ private module Stage4 {
pragma[nomagic]
private predicate storeStepFwd(
- Node node1, Ap ap1, TypedContent tc, Node node2, Ap ap2, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) {
fwdFlowStore(node1, ap1, tc, node2, _, _, config) and
ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, config)
}
- private predicate readStepFwd(Node n1, Ap ap1, Content c, Node n2, Ap ap2, Configuration config) {
+ private predicate readStepFwd(
+ NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
+ ) {
fwdFlowRead(ap1, c, n1, n2, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
- exists(Ap argAp0, Node out, Cc cc, ApOption argAp, Ap ap |
+ exists(Ap argAp0, NodeEx out, Cc cc, ApOption argAp, Ap ap |
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
@@ -2477,7 +2625,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughIntoCall(
- DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
+ DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, _, _, _, pragma[only_bind_into](config)) and
@@ -2494,41 +2642,41 @@ private module Stage4 {
* the access path of the returned value.
*/
pragma[nomagic]
- predicate revFlow(Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
+ predicate revFlow(NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config) {
revFlow0(node, toReturn, returnAp, ap, config) and
fwdFlow(node, _, _, ap, config)
}
pragma[nomagic]
private predicate revFlow0(
- Node node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
+ NodeEx node, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
fwdFlow(node, _, _, ap, config) and
- config.isSink(node) and
+ sinkNode(node, config) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
- exists(Node mid |
+ exists(NodeEx mid |
localStep(node, mid, true, _, config, _) and
revFlow(mid, toReturn, returnAp, ap, config)
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
- exists(Node mid |
+ exists(NodeEx mid |
jumpStep(node, mid, config) and
revFlow(mid, _, _, ap, config) and
toReturn = false and
returnAp = apNone()
)
or
- exists(Node mid, ApNil nil |
+ exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
@@ -2544,7 +2692,7 @@ private module Stage4 {
)
or
// read
- exists(Node mid, Ap ap0 |
+ exists(NodeEx mid, Ap ap0 |
revFlow(mid, toReturn, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config)
)
@@ -2568,7 +2716,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowStore(
- Ap ap0, Content c, Ap ap, Node node, TypedContent tc, Node mid, boolean toReturn,
+ Ap ap0, Content c, Ap ap, NodeEx node, TypedContent tc, NodeEx mid, boolean toReturn,
ApOption returnAp, Configuration config
) {
revFlow(mid, toReturn, returnAp, ap0, config) and
@@ -2582,7 +2730,7 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
- exists(Node mid, Ap tail0 |
+ exists(NodeEx mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
@@ -2591,10 +2739,10 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowOut(
- DataFlowCall call, ReturnNodeExt ret, boolean toReturn, ApOption returnAp, Ap ap,
+ DataFlowCall call, RetNodeEx ret, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
) {
- exists(Node out, boolean allowsFieldFlow |
+ exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
@@ -2603,8 +2751,10 @@ private module Stage4 {
}
pragma[nomagic]
- private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ private predicate revFlowInNotToReturn(
+ ArgNodeEx arg, ApOption returnAp, Ap ap, Configuration config
+ ) {
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
@@ -2614,9 +2764,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNodeEx arg, Ap returnAp, Ap ap, Configuration config
) {
- exists(ParamNode p, boolean allowsFieldFlow |
+ exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2633,7 +2783,7 @@ private module Stage4 {
private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ReturnNodeExt ret, CcCall ccc |
+ exists(RetNodeEx ret, CcCall ccc |
revFlowOut(call, ret, toReturn, returnAp, ap, config) and
fwdFlow(ret, ccc, apSome(_), ap, config) and
ccc.matchesCall(call)
@@ -2642,16 +2792,17 @@ private module Stage4 {
pragma[nomagic]
predicate storeStepCand(
- Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
+ NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
+ Configuration config
) {
exists(Ap ap2, Content c |
- store(node1, tc, node2, contentType) and
+ store(node1, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
}
- predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
+ predicate readStepCand(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
@@ -2660,7 +2811,7 @@ private module Stage4 {
)
}
- predicate revFlow(Node node, Configuration config) { revFlow(node, _, _, _, config) }
+ predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, config) }
private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) {
storeStepFwd(_, ap, tc, _, _, config)
@@ -2672,20 +2823,21 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
- c = getNodeEnclosingCallable(p)
+ c = p.getEnclosingCallable()
}
- predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
- exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
+ predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
+ exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
- c = getNodeEnclosingCallable(ret) and
- revFlow(ret, true, apSome(_), ap0, config) and
+ c = ret.getEnclosingCallable() and
+ revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
+ pragma[only_bind_into](config)) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
- p.isParameterOf(_, pos) and
+ p.getPosition() = pos and
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
@@ -2693,7 +2845,7 @@ private module Stage4 {
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
- exists(Ap returnAp0, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap |
+ exists(Ap returnAp0, ArgNodeEx arg, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(arg, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, arg, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
@@ -2702,16 +2854,16 @@ private module Stage4 {
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
- nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | fwdFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
- tuples = count(Node n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
+ tuples = count(NodeEx n, Cc cc, ApOption argAp, Ap ap | fwdFlow(n, cc, argAp, ap, config))
or
fwd = false and
- nodes = count(Node node | revFlow(node, _, _, _, config)) and
+ nodes = count(NodeEx node | revFlow(node, _, _, _, config)) and
fields = count(TypedContent f0 | consCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
- tuples = count(Node n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
+ tuples = count(NodeEx n, boolean b, ApOption retAp, Ap ap | revFlow(n, b, retAp, ap, config))
}
/* End: Stage 4 logic. */
}
@@ -2721,18 +2873,18 @@ private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
-private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
+private predicate nodeMayUseSummary(NodeEx n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
- getNodeEnclosingCallable(n) = c
+ n.getEnclosingCallable() = c
)
}
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParamNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNodeEx p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2753,7 +2905,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParamNode p;
+ private ParamNodeEx p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2786,7 +2938,9 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
- strictcount(Node n | Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config))
+ strictcount(NodeEx n |
+ Stage4::revFlow(n, _, _, apa, config) or nodeMayUseSummary(n, apa, config)
+ )
}
/**
@@ -2878,13 +3032,13 @@ private newtype TAccessPath =
}
private newtype TPathNode =
- TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
+ TPathNodeMid(NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2893,12 +3047,12 @@ private newtype TPathNode =
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
- TPathNodeSink(Node node, Configuration config) {
- pragma[only_bind_into](config).isSink(node) and
+ TPathNodeSink(NodeEx node, Configuration config) {
+ sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
- config.isSource(node)
+ sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
@@ -3099,15 +3253,17 @@ class PathNode extends TPathNode {
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private predicate isHidden() {
- hiddenNode(this.getNode()) and
+ hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
not this.isSource() and
not this instanceof PathNodeSink
+ or
+ this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
}
private PathNode getASuccessorIfHidden() {
@@ -3129,6 +3285,8 @@ class PathNode extends TPathNode {
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
+ abstract NodeEx getNodeEx();
+
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -3143,14 +3301,14 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
- override string toString() { result = this.getNode().toString() + ppAp() }
+ override string toString() { result = this.getNodeEx().toString() + ppAp() }
- override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() }
+ override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -3180,7 +3338,7 @@ module PathGraph {
* a `CallContext`, and a `Configuration`.
*/
private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
- Node node;
+ NodeEx node;
CallContext cc;
SummaryCtx sc;
AccessPath ap;
@@ -3188,7 +3346,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3199,7 +3357,8 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override Configuration getConfiguration() { result = config }
private PathNodeMid getSuccMid() {
- pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
+ pathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx(),
+ result.getAp()) and
result.getConfiguration() = unbindConf(this.getConfiguration())
}
@@ -3210,7 +3369,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
- mid.getNode() = sink.getNode() and
+ mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
@@ -3218,7 +3377,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
}
override predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
@@ -3231,31 +3390,35 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
* excluding the `CallContext`.
*/
private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
- Node node;
+ NodeEx node;
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
- override Node getNode() { result = node }
+ override NodeEx getNodeEx() { result = node }
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
- override predicate isSource() { config.isSource(node) }
+ override predicate isSource() { sourceNode(node, config) }
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
-private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
- midnode = mid.getNode() and
+private predicate pathStep(
+ PathNodeMid mid, NodeEx node, CallContext cc, SummaryCtx sc, AccessPath ap
+) {
+ exists(AccessPath ap0, NodeEx midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNodeEx() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
- localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
+ localCC =
+ getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
+ midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3265,16 +3428,16 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
ap0 instanceof AccessPathNil
)
or
- jumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = mid.getAp()
or
- additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
+ additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeDataFlowType(node))
+ ap = TAccessPathNil(node.getDataFlowType())
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3291,20 +3454,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pragma[nomagic]
private predicate pathReadStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
tc = ap0.getHead() and
- Stage4::readStepCand(mid.getNode(), tc.getContent(), node, mid.getConfiguration()) and
+ Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate pathStoreStep(
- PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
+ PathNodeMid mid, NodeEx node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
- Stage4::storeStepCand(mid.getNode(), _, tc, node, _, mid.getConfiguration()) and
+ Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -3312,7 +3475,7 @@ private predicate pathOutOfCallable0(
PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPathApprox apa,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
apa = mid.getAp().getApprox() and
@@ -3335,10 +3498,10 @@ private predicate pathOutOfCallable1(
}
pragma[noinline]
-private Node getAnOutNodeFlow(
+private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
- result = kind.getAnOutNode(call) and
+ result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, _, apa, config)
}
@@ -3347,7 +3510,7 @@ private Node getAnOutNodeFlow(
* is a return from a callable and is recorded by `cc`, if needed.
*/
pragma[noinline]
-private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
+private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) {
exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config |
pathOutOfCallable1(mid, call, kind, cc, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
@@ -3362,7 +3525,7 @@ private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -3374,7 +3537,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParamNode p |
+ exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3398,7 +3561,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3423,8 +3586,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
- exists(PathNodeMid mid, ReturnNodeExt ret, int pos |
- mid.getNode() = ret and
+ exists(PathNodeMid mid, RetNodeEx ret, int pos |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
@@ -3452,7 +3615,7 @@ private predicate pathThroughCallable0(
* The context `cc` is restored to its value prior to entering the callable.
*/
pragma[noinline]
-private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
+private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
@@ -3470,9 +3633,9 @@ private predicate flowsTo(
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
- flowsource.getNode() = source and
+ flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
- flowsink.getNode() = sink
+ flowsink.getNodeEx().asNode() = sink
}
/**
@@ -3487,13 +3650,13 @@ predicate flowsTo(Node source, Node sink, Configuration configuration) {
private predicate finalStats(boolean fwd, int nodes, int fields, int conscand, int tuples) {
fwd = true and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0)) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0)) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
tuples = count(PathNode pn)
or
fwd = false and
- nodes = count(Node n0 | exists(PathNode pn | pn.getNode() = n0 and reach(pn))) and
+ nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
tuples = count(PathNode pn | reach(pn))
@@ -3530,19 +3693,19 @@ predicate stageStats(
private module FlowExploration {
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) {
- exists(Node node1, Node node2 |
+ exists(NodeEx node1, NodeEx node2 |
jumpStep(node1, node2, config)
or
additionalJumpStep(node1, node2, config)
or
// flow into callable
- viableParamArg(_, node2, node1)
+ viableParamArgEx(_, node2, node1)
or
// flow out of a callable
- viableReturnPosOut(_, getReturnPosition(node1), node2)
+ viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2)
|
- c1 = getNodeEnclosingCallable(node1) and
- c2 = getNodeEnclosingCallable(node2) and
+ c1 = node1.getEnclosingCallable() and
+ c2 = node2.getEnclosingCallable() and
c1 != c2
)
}
@@ -3694,7 +3857,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParamNode p)
+ TSummaryCtx1Param(ParamNodeEx p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3710,25 +3873,25 @@ private module FlowExploration {
private newtype TPartialPathNode =
TPartialPathNodeFwd(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
- distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
- Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
+ NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
@@ -3737,23 +3900,23 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContentCached(node, ap.getHead()) and
+ not clearsContentCached(node.asNode(), ap.getHead()) and
not fullBarrier(node, config) and
- distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
+ distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
private predicate partialPathNodeMk0(
- Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
+ NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContentCached(node, ap.getHead().getContent()) and
- if node instanceof CastingNode
- then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
+ if node.asNode() instanceof CastingNode
+ then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
}
@@ -3763,13 +3926,15 @@ private module FlowExploration {
*/
class PartialPathNode extends TPartialPathNode {
/** Gets a textual representation of this element. */
- string toString() { result = this.getNode().toString() + this.ppAp() }
+ string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
- string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() }
+ string toStringWithContext() {
+ result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
+ }
/**
* Holds if this element is at the specified location.
@@ -3781,11 +3946,16 @@ private module FlowExploration {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
- Node getNode() { none() }
+ final Node getNode() { this.getNodeEx().projectToNode() = result }
+
+ private NodeEx getNodeEx() {
+ result = this.(PartialPathNodeFwd).getNodeEx() or
+ result = this.(PartialPathNodeRev).getNodeEx()
+ }
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
@@ -3798,7 +3968,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
- result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
/**
@@ -3806,7 +3976,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
- result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
+ result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
@@ -3838,7 +4008,7 @@ private module FlowExploration {
}
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
- Node node;
+ NodeEx node;
CallContext cc;
TSummaryCtx1 sc1;
TSummaryCtx2 sc2;
@@ -3847,7 +4017,7 @@ private module FlowExploration {
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
CallContext getCallContext() { result = cc }
@@ -3860,12 +4030,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeFwd getASuccessor() {
- partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
+ partialPathStep(this, result.getNodeEx(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
- config.isSource(node) and
+ sourceNode(node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
@@ -3874,7 +4044,7 @@ private module FlowExploration {
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
- Node node;
+ NodeEx node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
@@ -3882,7 +4052,7 @@ private module FlowExploration {
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
- override Node getNode() { result = node }
+ NodeEx getNodeEx() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
@@ -3893,12 +4063,12 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
- revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
+ revPartialPathStep(result, this.getNodeEx(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
- config.isSink(node) and
+ sinkNode(node, config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
@@ -3906,40 +4076,40 @@ private module FlowExploration {
}
private predicate partialPathStep(
- PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
+ PartialPathNodeFwd mid, NodeEx node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
(
- localFlowStep(mid.getNode(), node, config) and
+ localFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(mid.getNode(), node, config) and
+ additionalLocalFlowStep(mid.getNodeEx(), node, config) and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
)
or
- jumpStep(mid.getNode(), node, config) and
+ jumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(mid.getNode(), node, config) and
+ additionalJumpStep(mid.getNodeEx(), node, config) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeDataFlowType(node)) and
+ ap = TPartialNil(node.getDataFlowType()) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3952,8 +4122,7 @@ private module FlowExploration {
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
- apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeDataFlowType(node))
+ apConsFwd(ap, tc, ap0, config)
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3972,12 +4141,13 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
- PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
+ PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
+ PartialAccessPath ap2
) {
- exists(Node midNode, DataFlowType contentType |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, DataFlowType contentType |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- store(midNode, tc, node, contentType) and
+ store(midNode, tc, node, contentType, mid.getConfiguration()) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -3996,15 +4166,15 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
- PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
+ PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- read(midNode, tc.getContent(), node) and
+ read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
ap.getHead() = tc and
- config = mid.getConfiguration() and
+ pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
@@ -4013,7 +4183,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
- pos = getReturnPosition(mid.getNode()) and
+ pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and
innercc = mid.getCallContext() and
innercc instanceof CallContextNoCall and
ap = mid.getAp() and
@@ -4036,12 +4206,12 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
|
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
@@ -4051,7 +4221,7 @@ private module FlowExploration {
Configuration config
) {
exists(ArgNode arg |
- arg = mid.getNode() and
+ arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
@@ -4069,7 +4239,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -4090,8 +4260,8 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
- mid.getNode() = ret and
+ exists(PartialPathNodeFwd mid, RetNodeEx ret |
+ mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
sc1 = mid.getSummaryCtx1() and
@@ -4106,45 +4276,45 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
- partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
+ exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ partialPathIntoCallable(mid, _, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
}
private predicate partialPathThroughCallable(
- PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
+ PartialPathNodeFwd mid, NodeEx out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
- out = kind.getAnOutNode(call)
+ out.asNode() = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
- PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
+ PartialPathNodeRev mid, NodeEx node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
- localFlowStep(node, mid.getNode(), config) and
+ localFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalLocalFlowStep(node, mid.getNode(), config) and
+ additionalLocalFlowStep(node, mid.getNodeEx(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
- jumpStep(node, mid.getNode(), config) and
+ jumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
- additionalJumpStep(node, mid.getNode(), config) and
+ additionalJumpStep(node, mid.getNodeEx(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
@@ -4163,9 +4333,9 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParamNode p |
- mid.getNode() = p and
- viableParamArg(_, p, node) and
+ exists(ParamNodeEx p |
+ mid.getNodeEx() = p and
+ viableParamArgEx(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
@@ -4176,7 +4346,7 @@ private module FlowExploration {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
- pos = getReturnPosition(node)
+ pos = getReturnPosition(node.asNode())
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
@@ -4186,12 +4356,13 @@ private module FlowExploration {
pragma[inline]
private predicate revPartialPathReadStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
+ PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node,
+ RevPartialAccessPath ap2
) {
- exists(Node midNode |
- midNode = mid.getNode() and
+ exists(NodeEx midNode |
+ midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
- read(node, c, midNode) and
+ read(node, c, midNode, mid.getConfiguration()) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
@@ -4209,12 +4380,12 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathStoreStep(
- PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
+ PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
- exists(Node midNode, TypedContent tc |
- midNode = mid.getNode() and
+ exists(NodeEx midNode, TypedContent tc |
+ midNode = mid.getNodeEx() and
ap = mid.getAp() and
- store(node, tc, midNode, _) and
+ store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
@@ -4226,9 +4397,9 @@ private module FlowExploration {
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
- exists(Node out |
- mid.getNode() = out and
- viableReturnPosOut(call, pos, out) and
+ exists(NodeEx out |
+ mid.getNodeEx() = out and
+ viableReturnPosOutEx(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
@@ -4241,9 +4412,9 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParamNode p |
- mid.getNode() = p and
- p.isParameterOf(_, pos) and
+ exists(PartialPathNodeRev mid, ParamNodeEx p |
+ mid.getNodeEx() = p and
+ p.getPosition() = pos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
@@ -4264,11 +4435,11 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
- node.argumentOf(call, pos)
+ node.asNode().(ArgNode).argumentOf(call, pos)
)
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
index 462e89ac9ed..728f7b56c42 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
@@ -724,7 +724,6 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
- read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
@@ -1118,6 +1117,44 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
}
+/**
+ * Checks whether `inner` can return to `call` in the call context `innercc`.
+ * Assumes a context of `inner = viableCallableExt(call)`.
+ */
+bindingset[innercc, inner, call]
+predicate checkCallContextReturn(CallContext innercc, DataFlowCallable inner, DataFlowCall call) {
+ innercc instanceof CallContextAny
+ or
+ exists(DataFlowCallable c0, DataFlowCall call0 |
+ callEnclosingCallable(call0, inner) and
+ innercc = TReturn(c0, call0) and
+ c0 = prunedViableImplInCallContextReverse(call0, call)
+ )
+}
+
+/**
+ * Checks whether `call` can resolve to `calltarget` in the call context `cc`.
+ * Assumes a context of `calltarget = viableCallableExt(call)`.
+ */
+bindingset[cc, call, calltarget]
+predicate checkCallContextCall(CallContext cc, DataFlowCall call, DataFlowCallable calltarget) {
+ exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
+ if reducedViableImplInCallContext(call, _, ctx)
+ then calltarget = prunedViableImplInCallContext(call, ctx)
+ else any()
+ )
+ or
+ cc instanceof CallContextSomeCall
+ or
+ cc instanceof CallContextAny
+ or
+ cc instanceof CallContextReturn
+}
+
+/**
+ * Resolves a return from `callable` in `cc` to `call`. This is equivalent to
+ * `callable = viableCallableExt(call) and checkCallContextReturn(cc, callable, call)`.
+ */
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallableExt(call)
@@ -1129,6 +1166,10 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
)
}
+/**
+ * Resolves a call from `call` in `cc` to `result`. This is equivalent to
+ * `result = viableCallableExt(call) and checkCallContextCall(cc, call, result)`.
+ */
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
index 6373382a204..ca4d0fa98e7 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
@@ -1258,12 +1258,33 @@ private module ReturnNodes {
SummaryReturnNode() {
FlowSummaryImpl::Private::summaryReturnNode(this, rk) and
not rk instanceof JumpReturnKind
+ or
+ exists(Parameter p, int pos |
+ summaryPostUpdateNodeIsOutOrRef(this, p) and
+ pos = p.getPosition()
+ |
+ p.isOut() and rk.(OutReturnKind).getPosition() = pos
+ or
+ p.isRef() and rk.(RefReturnKind).getPosition() = pos
+ )
}
override ReturnKind getKind() { result = rk }
}
}
+/**
+ * Holds if summary node `n` is a post-update node for `out`/`ref` parameter `p`.
+ * In this case we adjust it to instead be a return node.
+ */
+private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) {
+ exists(ParameterNode pn |
+ FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and
+ pn.getParameter() = p and
+ p.isOutOrRef()
+ )
+}
+
import ReturnNodes
/** A data-flow node that represents the output of a call. */
@@ -1841,7 +1862,10 @@ private module PostUpdateNodes {
}
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
- SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, _) }
+ SummaryPostUpdateNode() {
+ FlowSummaryImpl::Private::summaryPostUpdateNode(this, _) and
+ not summaryPostUpdateNodeIsOutOrRef(this, _)
+ }
override Node getPreUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this, result)
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
index ddafb23274b..523516e60f8 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
@@ -9,7 +9,7 @@
private import FlowSummaryImplSpecific
private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
-private import DataFlowImplCommon as DataFlowImplCommon
+private import DataFlowImplCommon
/** Provides classes and predicates for defining flow summaries. */
module Public {
@@ -295,7 +295,7 @@ module Private {
or
exists(int i |
parameterReadState(c, state, i) and
- result.(ParameterNode).isParameterOf(c, i)
+ result.(ParamNode).isParameterOf(c, i)
)
)
}
@@ -375,7 +375,9 @@ module Private {
or
exists(ReturnKind rk |
head = TReturnSummaryComponent(rk) and
- result = getCallbackReturnType(getNodeType(summaryNodeInputState(c, s.drop(1))), rk)
+ result =
+ getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
+ s.drop(1))), rk)
)
)
or
@@ -392,7 +394,9 @@ module Private {
)
or
exists(int i | head = TParameterSummaryComponent(i) |
- result = getCallbackParameterType(getNodeType(summaryNodeOutputState(c, s.drop(1))), i)
+ result =
+ getCallbackParameterType(getNodeType(summaryNodeOutputState(pragma[only_bind_out](c),
+ s.drop(1))), i)
)
)
)
@@ -417,7 +421,7 @@ module Private {
}
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
- predicate summaryPostUpdateNode(Node post, ParameterNode pre) {
+ predicate summaryPostUpdateNode(Node post, ParamNode pre) {
exists(SummarizedCallable c, int i |
isParameterPostUpdate(post, c, i) and
pre.isParameterOf(c, i)
@@ -489,7 +493,7 @@ module Private {
* Holds if values stored inside content `c` are cleared when passed as
* input of type `input` in `call`.
*/
- predicate summaryClearsContent(ArgumentNode arg, Content c) {
+ predicate summaryClearsContent(ArgNode arg, Content c) {
exists(DataFlowCall call, int i |
viableCallable(call).(SummarizedCallable).clearsContent(i, c) and
arg.argumentOf(call, i)
@@ -497,9 +501,7 @@ module Private {
}
pragma[nomagic]
- private ParameterNode summaryArgParam(
- ArgumentNode arg, DataFlowImplCommon::ReturnKindExt rk, DataFlowImplCommon::OutNodeExt out
- ) {
+ private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
exists(DataFlowCall call, int pos, SummarizedCallable callable |
arg.argumentOf(call, pos) and
viableCallable(call) = callable and
@@ -515,8 +517,8 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
- predicate summaryThroughStep(ArgumentNode arg, Node out, boolean preservesValue) {
- exists(DataFlowImplCommon::ReturnKindExt rk, DataFlowImplCommon::ReturnNodeExt ret |
+ predicate summaryThroughStep(ArgNode arg, Node out, boolean preservesValue) {
+ exists(ReturnKindExt rk, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, rk, out), ret, preservesValue) and
ret.getKind() = rk
)
@@ -529,8 +531,8 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
- predicate summaryGetterStep(ArgumentNode arg, Content c, Node out) {
- exists(DataFlowImplCommon::ReturnKindExt rk, Node mid, DataFlowImplCommon::ReturnNodeExt ret |
+ predicate summaryGetterStep(ArgNode arg, Content c, Node out) {
+ exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and
summaryLocalStep(mid, ret, _) and
ret.getKind() = rk
@@ -544,8 +546,8 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
- predicate summarySetterStep(ArgumentNode arg, Content c, Node out) {
- exists(DataFlowImplCommon::ReturnKindExt rk, Node mid, DataFlowImplCommon::ReturnNodeExt ret |
+ predicate summarySetterStep(ArgNode arg, Content c, Node out) {
+ exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and
summaryStoreStep(mid, c, ret) and
ret.getKind() = rk
@@ -559,12 +561,9 @@ module Private {
* definition of `clearsContent()`.
*/
predicate summaryStoresIntoArg(Content c, Node arg) {
- exists(
- DataFlowImplCommon::ParamUpdateReturnKind rk, DataFlowImplCommon::ReturnNodeExt ret,
- PostUpdateNode out
- |
+ exists(ParamUpdateReturnKind rk, ReturnNodeExt ret, PostUpdateNode out |
exists(DataFlowCall call, SummarizedCallable callable |
- DataFlowImplCommon::getNodeEnclosingCallable(ret) = callable and
+ getNodeEnclosingCallable(ret) = callable and
viableCallable(call) = callable and
summaryStoreStep(_, c, ret) and
ret.getKind() = pragma[only_bind_into](rk) and
@@ -643,6 +642,13 @@ module Private {
)
}
+ /**
+ * Holds if `spec` specifies summary component stack `stack`.
+ */
+ predicate interpretSpec(string spec, SummaryComponentStack stack) {
+ interpretSpec(spec, 0, stack)
+ }
+
private predicate interpretSpec(string spec, int idx, SummaryComponentStack stack) {
exists(string c |
relevantSpec(spec) and
@@ -681,8 +687,8 @@ module Private {
) {
exists(string inSpec, string outSpec, string kind |
summaryElement(this, inSpec, outSpec, kind) and
- interpretSpec(inSpec, 0, input) and
- interpretSpec(outSpec, 0, output)
+ interpretSpec(inSpec, input) and
+ interpretSpec(outSpec, output)
|
kind = "value" and preservesValue = true
or
@@ -736,21 +742,17 @@ module Private {
specSplit(output, c, idx)
|
exists(int pos |
- node.asNode()
- .(PostUpdateNode)
- .getPreUpdateNode()
- .(ArgumentNode)
- .argumentOf(mid.asCall(), pos)
+ node.asNode().(PostUpdateNode).getPreUpdateNode().(ArgNode).argumentOf(mid.asCall(), pos)
|
c = "Argument" or parseArg(c, pos)
)
or
- exists(int pos | node.asNode().(ParameterNode).isParameterOf(mid.asCallable(), pos) |
+ exists(int pos | node.asNode().(ParamNode).isParameterOf(mid.asCallable(), pos) |
c = "Parameter" or parseParam(c, pos)
)
or
c = "ReturnValue" and
- node.asNode() = getAnOutNode(mid.asCall(), getReturnValueKind())
+ node.asNode() = getAnOutNodeExt(mid.asCall(), TValueReturn(getReturnValueKind()))
or
interpretOutputSpecific(c, mid, node)
)
@@ -765,15 +767,15 @@ module Private {
interpretInput(input, idx + 1, ref, mid) and
specSplit(input, c, idx)
|
- exists(int pos | node.asNode().(ArgumentNode).argumentOf(mid.asCall(), pos) |
+ exists(int pos | node.asNode().(ArgNode).argumentOf(mid.asCall(), pos) |
c = "Argument" or parseArg(c, pos)
)
or
- exists(ReturnNode ret |
+ exists(ReturnNodeExt ret |
c = "ReturnValue" and
ret = node.asNode() and
- ret.getKind() = getReturnValueKind() and
- mid.asCallable() = DataFlowImplCommon::getNodeEnclosingCallable(ret)
+ ret.getKind().(ValueReturnKind).getKind() = getReturnValueKind() and
+ mid.asCallable() = getNodeEnclosingCallable(ret)
)
or
interpretInputSpecific(c, mid, node)
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
index efab6eb9e3c..b0f67e8692f 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -7,9 +7,11 @@ private import semmle.code.csharp.frameworks.system.linq.Expressions
private import DataFlowDispatch
private import DataFlowPrivate
private import DataFlowPublic
+private import DataFlowImplCommon
private import FlowSummaryImpl::Private
private import FlowSummaryImpl::Public
private import semmle.code.csharp.Unification
+private import semmle.code.csharp.dataflow.ExternalFlow
/** Holds is `i` is a valid parameter position. */
predicate parameterPosition(int i) { i in [-1 .. any(Parameter p).getPosition()] }
@@ -82,7 +84,40 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, and kind `kind`.
*/
-predicate summaryElement(DataFlowCallable c, string input, string output, string kind) { none() }
+predicate summaryElement(DataFlowCallable c, string input, string output, string kind) {
+ exists(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
+ |
+ summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
+ c = interpretElement(namespace, type, subtypes, name, signature, ext)
+ )
+}
+
+/**
+ * Holds if an external source specification exists for `e` with output specification
+ * `output` and kind `kind`.
+ */
+predicate sourceElement(Element e, string output, string kind) {
+ exists(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
+ |
+ sourceModel(namespace, type, subtypes, name, signature, ext, output, kind) and
+ e = interpretElement(namespace, type, subtypes, name, signature, ext)
+ )
+}
+
+/**
+ * Holds if an external sink specification exists for `n` with input specification
+ * `input` and kind `kind`.
+ */
+predicate sinkElement(Element e, string input, string kind) {
+ exists(
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
+ |
+ sinkModel(namespace, type, subtypes, name, signature, ext, input, kind) and
+ e = interpretElement(namespace, type, subtypes, name, signature, ext)
+ )
+}
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
@@ -102,18 +137,6 @@ SummaryComponent interpretComponentSpecific(string c) {
class SourceOrSinkElement = Element;
-/**
- * Holds if an external source specification exists for `e` with output specification
- * `output` and kind `kind`.
- */
-predicate sourceElement(Element e, string output, string kind) { none() }
-
-/**
- * Holds if an external sink specification exists for `n` with input specification
- * `input` and kind `kind`.
- */
-predicate sinkElement(Element e, string input, string kind) { none() }
-
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
NormalReturnKind getReturnValueKind() { any() }
@@ -137,7 +160,7 @@ class InterpretNode extends TInterpretNode {
DataFlowCallable asCallable() { result = this.asElement() }
/** Gets the target of this call, if any. */
- Callable getCallTarget() { result = this.asCall().getARuntimeTarget() }
+ Callable getCallTarget() { result = viableCallable(this.asCall()) }
/** Gets a textual representation of this node. */
string toString() {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll
index f37a4f2d074..884f4406d01 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll
@@ -284,8 +284,7 @@ private module SsaDefReaches {
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
- rnk = ssaRefRank(bb, i, v, SsaRead()) and
- variableRead(bb, i, v, _)
+ rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
index 462838abcd1..b304442b21d 100755
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
@@ -18,6 +18,13 @@ private import semmle.code.csharp.frameworks.WCF
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
+/**
+ * Holds if default `TaintTracking::Configuration`s should allow implicit reads
+ * of `c` at sinks and inputs to additional taint steps.
+ */
+bindingset[node]
+predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
+
deprecated predicate localAdditionalTaintStep = defaultAdditionalTaintStep/2;
private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll
index f37a4f2d074..884f4406d01 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll
@@ -284,8 +284,7 @@ private module SsaDefReaches {
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
- rnk = ssaRefRank(bb, i, v, SsaRead()) and
- variableRead(bb, i, v, _)
+ rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll
index b509fad9cd2..f4f73b8247c 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll
@@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
+ override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
+ (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
+ defaultImplicitTaintRead(node, c)
+ }
+
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll
index ef1f11bf7b5..24b3d12a5c9 100644
--- a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll
+++ b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll
@@ -2,6 +2,7 @@
import csharp
private import system.Reflection
+private import semmle.code.csharp.dataflow.ExternalFlow
/** The `System` namespace. */
class SystemNamespace extends Namespace {
@@ -200,6 +201,28 @@ class SystemInt32Struct extends IntType {
}
}
+/** Data flow for `System.Int32`. */
+private class SystemInt32FlowModelCsv extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "System;Int32;false;Parse;(System.String);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;Parse;(System.String,System.IFormatProvider);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;Parse;(System.String,System.Globalization.NumberStyles);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;Parse;(System.String,System.Globalization.NumberStyles,System.IFormatProvider);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;Parse;(System.ReadOnlySpan,System.Globalization.NumberStyles,System.IFormatProvider);;Element of Argument[0];ReturnValue;taint",
+ "System;Int32;false;TryParse;(System.String,System.Int32);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;TryParse;(System.String,System.Int32);;Argument[0];Argument[1];taint",
+ "System;Int32;false;TryParse;(System.ReadOnlySpan,System.Int32);;Element of Argument[0];ReturnValue;taint",
+ "System;Int32;false;TryParse;(System.ReadOnlySpan,System.Int32);;Element of Argument[0];Argument[1];taint",
+ "System;Int32;false;TryParse;(System.String,System.Globalization.NumberStyles,System.IFormatProvider,System.Int32);;Argument[0];ReturnValue;taint",
+ "System;Int32;false;TryParse;(System.String,System.Globalization.NumberStyles,System.IFormatProvider,System.Int32);;Argument[0];Argument[3];taint",
+ "System;Int32;false;TryParse;(System.ReadOnlySpan,System.Globalization.NumberStyles,System.IFormatProvider,System.Int32);;Element of Argument[0];ReturnValue;taint",
+ "System;Int32;false;TryParse;(System.ReadOnlySpan,System.Globalization.NumberStyles,System.IFormatProvider,System.Int32);;Element of Argument[0];Argument[3];taint"
+ ]
+ }
+}
+
/** The `System.InvalidCastException` class. */
class SystemInvalidCastExceptionClass extends SystemClass {
SystemInvalidCastExceptionClass() { this.hasName("InvalidCastException") }
diff --git a/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlow.qll b/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlow.qll
deleted file mode 100644
index 7bde645b8f8..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlow.qll
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * This module has classes and data flow configuration for working with symmetric encryption keys data flow.
- */
-
-import csharp
-
-module EncryptionKeyDataFlow {
- private import semmle.code.csharp.frameworks.system.security.cryptography.SymmetricAlgorithm
-
- /** Array of type Byte */
- class ByteArray extends ArrayType {
- ByteArray() { getElementType() instanceof ByteType }
- }
-
- /** Abstract class for all sources of keys */
- abstract class KeySource extends DataFlow::Node { }
-
- /**
- * A symmetric encryption sink is abstract base class for all ways to set a key for symmetric encryption.
- */
- abstract class SymmetricEncryptionKeySink extends DataFlow::Node {
- /** override to create a meaningful description of the sink */
- abstract string getDescription();
- }
-
- /**
- * A sanitizer for symmetric encryption key. If present, for example, key is properly constructed or retrieved from secret storage.
- */
- abstract class KeySanitizer extends DataFlow::ExprNode { }
-
- /**
- * Symmetric Algorithm, 'Key' property assigned a value
- */
- class SymmetricEncryptionKeyPropertySink extends SymmetricEncryptionKeySink {
- SymmetricEncryptionKeyPropertySink() {
- exists(SymmetricAlgorithm ag | asExpr() = ag.getKeyProperty().getAnAssignedValue())
- }
-
- override string getDescription() { result = "Key property assignment" }
- }
-
- /**
- * Symmetric Algorithm, CreateEncryptor method, rgbKey parameter
- */
- class SymmetricEncryptionCreateEncryptorSink extends SymmetricEncryptionKeySink {
- SymmetricEncryptionCreateEncryptorSink() {
- exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricEncryptor() |
- asExpr() = mc.getArgumentForName("rgbKey")
- )
- }
-
- override string getDescription() { result = "Encryptor(rgbKey, IV)" }
- }
-
- /**
- * Symmetric Algorithm, CreateDecryptor method, rgbKey parameter
- */
- class SymmetricEncryptionCreateDecryptorSink extends SymmetricEncryptionKeySink {
- SymmetricEncryptionCreateDecryptorSink() {
- exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricDecryptor() |
- asExpr() = mc.getArgumentForName("rgbKey")
- )
- }
-
- override string getDescription() { result = "Decryptor(rgbKey, IV)" }
- }
-
- /**
- * Symmetric Key Data Flow configuration.
- */
- class SymmetricKeyTaintTrackingConfiguration extends TaintTracking::Configuration {
- SymmetricKeyTaintTrackingConfiguration() { this = "SymmetricKeyTaintTracking" }
-
- /** Holds if the node is a key source. */
- override predicate isSource(DataFlow::Node src) { src instanceof KeySource }
-
- /** Holds if the node is a symmetric encryption key sink. */
- override predicate isSink(DataFlow::Node sink) { sink instanceof SymmetricEncryptionKeySink }
-
- /** Holds if the node is a key sanitizer. */
- override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof KeySanitizer }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlowQuery.qll b/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlowQuery.qll
new file mode 100644
index 00000000000..af1979c2d6d
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlowQuery.qll
@@ -0,0 +1,80 @@
+/**
+ * This module has classes and data flow configuration for working with symmetric encryption keys data flow.
+ */
+
+import csharp
+private import semmle.code.csharp.frameworks.system.security.cryptography.SymmetricAlgorithm
+
+/** Array of type Byte */
+class ByteArray extends ArrayType {
+ ByteArray() { getElementType() instanceof ByteType }
+}
+
+/** Abstract class for all sources of keys */
+abstract class KeySource extends DataFlow::Node { }
+
+/**
+ * A symmetric encryption sink is abstract base class for all ways to set a key for symmetric encryption.
+ */
+abstract class SymmetricEncryptionKeySink extends DataFlow::Node {
+ /** override to create a meaningful description of the sink */
+ abstract string getDescription();
+}
+
+/**
+ * A sanitizer for symmetric encryption key. If present, for example, key is properly constructed or retrieved from secret storage.
+ */
+abstract class KeySanitizer extends DataFlow::ExprNode { }
+
+/**
+ * Symmetric Algorithm, 'Key' property assigned a value
+ */
+class SymmetricEncryptionKeyPropertySink extends SymmetricEncryptionKeySink {
+ SymmetricEncryptionKeyPropertySink() {
+ exists(SymmetricAlgorithm ag | asExpr() = ag.getKeyProperty().getAnAssignedValue())
+ }
+
+ override string getDescription() { result = "Key property assignment" }
+}
+
+/**
+ * Symmetric Algorithm, CreateEncryptor method, rgbKey parameter
+ */
+class SymmetricEncryptionCreateEncryptorSink extends SymmetricEncryptionKeySink {
+ SymmetricEncryptionCreateEncryptorSink() {
+ exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricEncryptor() |
+ asExpr() = mc.getArgumentForName("rgbKey")
+ )
+ }
+
+ override string getDescription() { result = "Encryptor(rgbKey, IV)" }
+}
+
+/**
+ * Symmetric Algorithm, CreateDecryptor method, rgbKey parameter
+ */
+class SymmetricEncryptionCreateDecryptorSink extends SymmetricEncryptionKeySink {
+ SymmetricEncryptionCreateDecryptorSink() {
+ exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricDecryptor() |
+ asExpr() = mc.getArgumentForName("rgbKey")
+ )
+ }
+
+ override string getDescription() { result = "Decryptor(rgbKey, IV)" }
+}
+
+/**
+ * Symmetric Key Data Flow configuration.
+ */
+class SymmetricKeyTaintTrackingConfiguration extends TaintTracking::Configuration {
+ SymmetricKeyTaintTrackingConfiguration() { this = "SymmetricKeyTaintTracking" }
+
+ /** Holds if the node is a key source. */
+ override predicate isSource(DataFlow::Node src) { src instanceof KeySource }
+
+ /** Holds if the node is a symmetric encryption key sink. */
+ override predicate isSink(DataFlow::Node sink) { sink instanceof SymmetricEncryptionKeySink }
+
+ /** Holds if the node is a key sanitizer. */
+ override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof KeySanitizer }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorage.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorage.qll
deleted file mode 100644
index a0ce6d9d1ae..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorage.qll
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about cleartext storage of sensitive information.
- */
-
-import csharp
-
-module CleartextStorage {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.Web
- import semmle.code.csharp.security.SensitiveActions
- import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
-
- /**
- * A data flow source for cleartext storage of sensitive information.
- */
- abstract class Source extends DataFlow::ExprNode { }
-
- /**
- * A data flow sink for cleartext storage of sensitive information.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for cleartext storage of sensitive information.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for cleartext storage of sensitive information.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "ClearTextStorage" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of sensitive data. */
- class SensitiveExprSource extends Source {
- SensitiveExprSource() { this.getExpr() instanceof SensitiveExpr }
- }
-
- /** A call to any method whose name suggests that it encodes or encrypts the parameter. */
- class ProtectSanitizer extends Sanitizer {
- ProtectSanitizer() {
- exists(Method m, string s |
- this.getExpr().(MethodCall).getTarget() = m and
- m.getName().regexpMatch("(?i).*" + s + ".*")
- |
- s = "protect" or s = "encode" or s = "encrypt"
- )
- }
- }
-
- /**
- * An external location sink.
- */
- class ExternalSink extends Sink {
- ExternalSink() { this instanceof ExternalLocationSink }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorageQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorageQuery.qll
new file mode 100644
index 00000000000..0f241d0c69b
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/CleartextStorageQuery.qll
@@ -0,0 +1,61 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about cleartext storage of sensitive information.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.Web
+private import semmle.code.csharp.security.SensitiveActions
+private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
+
+/**
+ * A data flow source for cleartext storage of sensitive information.
+ */
+abstract class Source extends DataFlow::ExprNode { }
+
+/**
+ * A data flow sink for cleartext storage of sensitive information.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for cleartext storage of sensitive information.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for cleartext storage of sensitive information.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "ClearTextStorage" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of sensitive data. */
+class SensitiveExprSource extends Source {
+ SensitiveExprSource() { this.getExpr() instanceof SensitiveExpr }
+}
+
+/** A call to any method whose name suggests that it encodes or encrypts the parameter. */
+class ProtectSanitizer extends Sanitizer {
+ ProtectSanitizer() {
+ exists(Method m, string s |
+ this.getExpr().(MethodCall).getTarget() = m and
+ m.getName().regexpMatch("(?i).*" + s + ".*")
+ |
+ s = "protect" or s = "encode" or s = "encrypt"
+ )
+ }
+}
+
+/**
+ * An external location sink.
+ */
+class ExternalSink extends Sink {
+ ExternalSink() { this instanceof ExternalLocationSink }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjection.qll
deleted file mode 100644
index d58d851b7c8..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjection.qll
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about user input treated as code vulnerabilities.
- */
-
-import csharp
-
-module CodeInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.security.dataflow.flowsources.Local
- import semmle.code.csharp.frameworks.system.codedom.Compiler
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for user input treated as code vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for user input treated as code vulnerabilities.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for user input treated as code vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for user input treated as code vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "CodeInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** A source of local user input. */
- class LocalSource extends Source {
- LocalSource() { this instanceof LocalFlowSource }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-
- /**
- * A `source` argument to a call to `ICodeCompiler.CompileAssemblyFromSource*` which is a sink for
- * code injection vulnerabilities.
- */
- class CompileAssemblyFromSourceSink extends Sink {
- CompileAssemblyFromSourceSink() {
- exists(Method m, MethodCall mc |
- m.getName().matches("CompileAssemblyFromSource%") and
- m = any(SystemCodeDomCompilerICodeCompilerClass c).getAMethod() and
- mc = m.getAnOverrider*().getACall()
- |
- this.getExpr() = mc.getArgumentForName("source") or
- this.getExpr() = mc.getArgumentForName("sources")
- )
- }
- }
-
- /**
- * A `code` argument to a call to a method on `CSharpScript`.
- *
- * This class is provided by Roslyn, and allows dynamic evaluation of C#.
- */
- class RoslynCSharpScriptSink extends Sink {
- RoslynCSharpScriptSink() {
- exists(Class c |
- c.hasQualifiedName("Microsoft.CodeAnalysis.CSharp.Scripting", "CSharpScript")
- |
- this.getExpr() = c.getAMethod().getACall().getArgumentForName("code")
- )
- }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll
new file mode 100644
index 00000000000..39254fe6072
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll
@@ -0,0 +1,81 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about user input treated as code vulnerabilities.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.security.dataflow.flowsources.Local
+private import semmle.code.csharp.frameworks.system.codedom.Compiler
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for user input treated as code vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for user input treated as code vulnerabilities.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for user input treated as code vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for user input treated as code vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "CodeInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** A source of local user input. */
+class LocalSource extends Source {
+ LocalSource() { this instanceof LocalFlowSource }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
+
+/**
+ * A `source` argument to a call to `ICodeCompiler.CompileAssemblyFromSource*` which is a sink for
+ * code injection vulnerabilities.
+ */
+class CompileAssemblyFromSourceSink extends Sink {
+ CompileAssemblyFromSourceSink() {
+ exists(Method m, MethodCall mc |
+ m.getName().matches("CompileAssemblyFromSource%") and
+ m = any(SystemCodeDomCompilerICodeCompilerClass c).getAMethod() and
+ mc = m.getAnOverrider*().getACall()
+ |
+ this.getExpr() = mc.getArgumentForName("source") or
+ this.getExpr() = mc.getArgumentForName("sources")
+ )
+ }
+}
+
+/**
+ * A `code` argument to a call to a method on `CSharpScript`.
+ *
+ * This class is provided by Roslyn, and allows dynamic evaluation of C#.
+ */
+class RoslynCSharpScriptSink extends Sink {
+ RoslynCSharpScriptSink() {
+ exists(Class c | c.hasQualifiedName("Microsoft.CodeAnalysis.CSharp.Scripting", "CSharpScript") |
+ this.getExpr() = c.getAMethod().getACall().getArgumentForName("code")
+ )
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjection.qll
deleted file mode 100644
index 7d2a49784e1..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjection.qll
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about command injection vulnerabilities.
- */
-
-import csharp
-
-module CommandInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.Diagnostics
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A source specific to command injection vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A sink for command injection vulnerabilities.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for user input treated as code vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for command injection vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "CommandInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * A sink in `System.Diagnostic.Process` or its related classes.
- */
- class SystemProcessCommandInjectionSink extends Sink {
- SystemProcessCommandInjectionSink() {
- // Arguments passed directly to the `System.Diagnostics.Process.Start` method
- exists(SystemDiagnosticsProcessClass processClass |
- this.getExpr() = processClass.getAStartMethod().getAParameter().getAnAssignedArgument()
- )
- or
- // Values set on a `System.Diagnostics.ProcessStartInfo` class
- exists(SystemDiagnosticsProcessStartInfoClass startInfoClass |
- this.getExpr() = startInfoClass.getAConstructor().getACall().getAnArgument()
- or
- exists(Property p |
- p = startInfoClass.getArgumentsProperty() or
- p = startInfoClass.getFileNameProperty() or
- p = startInfoClass.getWorkingDirectoryProperty()
- |
- this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument()
- )
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll
new file mode 100644
index 00000000000..506bf9599b7
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll
@@ -0,0 +1,70 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about command injection vulnerabilities.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.Diagnostics
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A source specific to command injection vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A sink for command injection vulnerabilities.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for user input treated as code vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for command injection vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "CommandInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * A sink in `System.Diagnostic.Process` or its related classes.
+ */
+class SystemProcessCommandInjectionSink extends Sink {
+ SystemProcessCommandInjectionSink() {
+ // Arguments passed directly to the `System.Diagnostics.Process.Start` method
+ exists(SystemDiagnosticsProcessClass processClass |
+ this.getExpr() = processClass.getAStartMethod().getAParameter().getAnAssignedArgument()
+ )
+ or
+ // Values set on a `System.Diagnostics.ProcessStartInfo` class
+ exists(SystemDiagnosticsProcessStartInfoClass startInfoClass |
+ this.getExpr() = startInfoClass.getAConstructor().getACall().getAnArgument()
+ or
+ exists(Property p |
+ p = startInfoClass.getArgumentsProperty() or
+ p = startInfoClass.getFileNameProperty() or
+ p = startInfoClass.getWorkingDirectoryProperty()
+ |
+ this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument()
+ )
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll
deleted file mode 100644
index 21399d50237..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypass.qll
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about user-controlled bypass of sensitive
- * methods.
- */
-
-import csharp
-
-module UserControlledBypassOfSensitiveMethod {
- import semmle.code.csharp.controlflow.Guards
- import semmle.code.csharp.controlflow.BasicBlocks
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.System
- import semmle.code.csharp.frameworks.system.Net
- import semmle.code.csharp.security.SensitiveActions
-
- /**
- * A data flow source for user-controlled bypass of sensitive method.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for user-controlled bypass of sensitive method.
- */
- abstract class Sink extends DataFlow::ExprNode {
- /** Gets the 'MethodCall' which is considered sensitive. */
- abstract MethodCall getSensitiveMethodCall();
- }
-
- /**
- * A sanitizer for user-controlled bypass of sensitive method.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for user-controlled bypass of sensitive method.
- */
- class Configuration extends TaintTracking::Configuration {
- Configuration() { this = "UserControlledBypassOfSensitiveMethodConfiguration" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** The result of a reverse dns may be user-controlled. */
- class ReverseDnsSource extends Source {
- ReverseDnsSource() {
- this.asExpr().(MethodCall).getTarget() =
- any(SystemNetDnsClass dns).getGetHostByAddressMethod()
- }
- }
-
- pragma[noinline]
- private predicate conditionControlsCall0(
- SensitiveExecutionMethodCall call, Expr e, ControlFlow::SuccessorTypes::BooleanSuccessor s
- ) {
- forex(BasicBlock bb | bb = call.getAControlFlowNode().getBasicBlock() |
- e.controlsBlock(bb, s, _)
- )
- }
-
- private predicate conditionControlsCall(
- SensitiveExecutionMethodCall call, SensitiveExecutionMethod def, Expr e, boolean cond
- ) {
- exists(ControlFlow::SuccessorTypes::BooleanSuccessor s | cond = s.getValue() |
- conditionControlsCall0(call, e, s)
- ) and
- def = call.getTarget()
- }
-
- /**
- * Calls to a sensitive method that are controlled by a condition
- * on the given expression.
- */
- predicate conditionControlsMethod(SensitiveExecutionMethodCall call, Expr e) {
- exists(SensitiveExecutionMethod def, boolean cond |
- conditionControlsCall(call, def, e, cond) and
- // Exclude this condition if the other branch also contains a call to the same security
- // sensitive method.
- not conditionControlsCall(_, def, e, cond.booleanNot())
- )
- }
-
- /**
- * An expression which is a condition which controls access to a sensitive action.
- */
- class ConditionControllingSensitiveAction extends Sink {
- private MethodCall sensitiveMethodCall;
-
- ConditionControllingSensitiveAction() {
- // A condition used to guard a sensitive method call
- conditionControlsMethod(sensitiveMethodCall, this.getExpr())
- or
- // A condition used to guard a sensitive method call, where the condition is `EndsWith`,
- // `StartsWith` or `Contains` on a tainted value. Tracking from strings to booleans doesn't
- // make sense in all contexts, so this is restricted to this case.
- exists(MethodCall stringComparisonCall, string methodName |
- methodName = "EndsWith" or
- methodName = "StartsWith" or
- methodName = "Contains"
- |
- stringComparisonCall = any(SystemStringClass s).getAMethod(methodName).getACall() and
- conditionControlsMethod(sensitiveMethodCall, stringComparisonCall) and
- stringComparisonCall.getQualifier() = this.getExpr()
- )
- }
-
- override MethodCall getSensitiveMethodCall() { result = sensitiveMethodCall }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypassQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypassQuery.qll
new file mode 100644
index 00000000000..0ab459a80c8
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ConditionalBypassQuery.qll
@@ -0,0 +1,111 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about user-controlled bypass of sensitive
+ * methods.
+ */
+
+import csharp
+private import semmle.code.csharp.controlflow.Guards
+private import semmle.code.csharp.controlflow.BasicBlocks
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.csharp.frameworks.system.Net
+private import semmle.code.csharp.security.SensitiveActions
+
+/**
+ * A data flow source for user-controlled bypass of sensitive method.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for user-controlled bypass of sensitive method.
+ */
+abstract class Sink extends DataFlow::ExprNode {
+ /** Gets the 'MethodCall' which is considered sensitive. */
+ abstract MethodCall getSensitiveMethodCall();
+}
+
+/**
+ * A sanitizer for user-controlled bypass of sensitive method.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for user-controlled bypass of sensitive method.
+ */
+class Configuration extends TaintTracking::Configuration {
+ Configuration() { this = "UserControlledBypassOfSensitiveMethodConfiguration" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** The result of a reverse dns may be user-controlled. */
+class ReverseDnsSource extends Source {
+ ReverseDnsSource() {
+ this.asExpr().(MethodCall).getTarget() = any(SystemNetDnsClass dns).getGetHostByAddressMethod()
+ }
+}
+
+pragma[noinline]
+private predicate conditionControlsCall0(
+ SensitiveExecutionMethodCall call, Expr e, ControlFlow::SuccessorTypes::BooleanSuccessor s
+) {
+ forex(BasicBlock bb | bb = call.getAControlFlowNode().getBasicBlock() | e.controlsBlock(bb, s, _))
+}
+
+private predicate conditionControlsCall(
+ SensitiveExecutionMethodCall call, SensitiveExecutionMethod def, Expr e, boolean cond
+) {
+ exists(ControlFlow::SuccessorTypes::BooleanSuccessor s | cond = s.getValue() |
+ conditionControlsCall0(call, e, s)
+ ) and
+ def = call.getTarget()
+}
+
+/**
+ * Calls to a sensitive method that are controlled by a condition
+ * on the given expression.
+ */
+predicate conditionControlsMethod(SensitiveExecutionMethodCall call, Expr e) {
+ exists(SensitiveExecutionMethod def, boolean cond |
+ conditionControlsCall(call, def, e, cond) and
+ // Exclude this condition if the other branch also contains a call to the same security
+ // sensitive method.
+ not conditionControlsCall(_, def, e, cond.booleanNot())
+ )
+}
+
+/**
+ * An expression which is a condition which controls access to a sensitive action.
+ */
+class ConditionControllingSensitiveAction extends Sink {
+ private MethodCall sensitiveMethodCall;
+
+ ConditionControllingSensitiveAction() {
+ // A condition used to guard a sensitive method call
+ conditionControlsMethod(sensitiveMethodCall, this.getExpr())
+ or
+ // A condition used to guard a sensitive method call, where the condition is `EndsWith`,
+ // `StartsWith` or `Contains` on a tainted value. Tracking from strings to booleans doesn't
+ // make sense in all contexts, so this is restricted to this case.
+ exists(MethodCall stringComparisonCall, string methodName |
+ methodName = "EndsWith" or
+ methodName = "StartsWith" or
+ methodName = "Contains"
+ |
+ stringComparisonCall = any(SystemStringClass s).getAMethod(methodName).getACall() and
+ conditionControlsMethod(sensitiveMethodCall, stringComparisonCall) and
+ stringComparisonCall.getQualifier() = this.getExpr()
+ )
+ }
+
+ override MethodCall getSensitiveMethodCall() { result = sensitiveMethodCall }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformation.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformation.qll
deleted file mode 100644
index 19866738341..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformation.qll
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about private information flowing unencrypted to an external location.
- */
-
-import csharp
-
-module ExposureOfPrivateInformation {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
- import semmle.code.csharp.security.PrivateData
-
- /**
- * A data flow source for private information flowing unencrypted to an external location.
- */
- abstract class Source extends DataFlow::ExprNode { }
-
- /**
- * A data flow sink for private information flowing unencrypted to an external location.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for private information flowing unencrypted to an external location.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for private information flowing unencrypted to an external location.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "ExposureOfPrivateInformation" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- class PrivateDataSource extends Source {
- PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
- }
-
- class ExternalLocation extends Sink {
- ExternalLocation() { this instanceof ExternalLocationSink }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformationQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformationQuery.qll
new file mode 100644
index 00000000000..11a79878698
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ExposureOfPrivateInformationQuery.qll
@@ -0,0 +1,44 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about private information flowing unencrypted to an external location.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
+private import semmle.code.csharp.security.PrivateData
+
+/**
+ * A data flow source for private information flowing unencrypted to an external location.
+ */
+abstract class Source extends DataFlow::ExprNode { }
+
+/**
+ * A data flow sink for private information flowing unencrypted to an external location.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for private information flowing unencrypted to an external location.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for private information flowing unencrypted to an external location.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "ExposureOfPrivateInformation" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+private class PrivateDataSource extends Source {
+ PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
+}
+
+private class ExternalLocation extends Sink {
+ ExternalLocation() { this instanceof ExternalLocationSink }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIs.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll
similarity index 95%
rename from csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIs.qll
rename to csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll
index 295c3e58869..bccd71d7096 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIs.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll
@@ -4,10 +4,10 @@
*/
import csharp
-import semmle.code.csharp.dataflow.flowsources.Remote
-import semmle.code.csharp.dataflow.TaintTracking
-import semmle.code.csharp.frameworks.System
-import semmle.code.csharp.dataflow.FlowSummary
+private import semmle.code.csharp.dataflow.flowsources.Remote
+private import semmle.code.csharp.dataflow.TaintTracking
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.csharp.dataflow.FlowSummary
/**
* A callable that is considered a "safe" external API from a security perspective.
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll
deleted file mode 100644
index 0ffabe60588..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about hard coded credentials.
- */
-
-import csharp
-
-module HardcodedCredentials {
- import semmle.code.csharp.commons.ComparisonTest
- import semmle.code.csharp.frameworks.System
- import semmle.code.csharp.frameworks.Moq
- import semmle.code.csharp.frameworks.system.web.Security
- import semmle.code.csharp.frameworks.system.security.cryptography.X509Certificates
- import semmle.code.csharp.frameworks.Test
-
- /**
- * A data flow source for hard coded credentials.
- */
- abstract class Source extends DataFlow::ExprNode { }
-
- /**
- * A data flow sink for hard coded credentials.
- */
- abstract class Sink extends DataFlow::ExprNode {
- /**
- * Gets a description of this sink, including a placeholder for the sink and a placeholder for
- * the supplementary element.
- */
- abstract string getSinkDescription();
-
- /** Gets an element that is used as supplementary data in the description. */
- abstract Element getSupplementaryElement();
-
- /** Gets the sink name to use when displaying the sink. */
- abstract string getSinkName();
- }
-
- /**
- * A sanitizer for hard coded credentials.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for hard coded credentials.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "HardcodedCredentials" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) {
- sink instanceof Sink and
- // Ignore values that are ultimately returned by mocks, as they don't represent "real"
- // credentials.
- not any(ReturnedByMockObject mock).getAMemberInitializationValue() = sink.asExpr() and
- not any(ReturnedByMockObject mock).getAnArgument() = sink.asExpr()
- }
-
- override predicate hasFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
- super.hasFlowPath(source, sink) and
- // Exclude hard-coded credentials in tests if they only flow to calls to methods with a name
- // like "Add*" "Create*" or "Update*". The rationale is that hard-coded credentials within
- // tests that are only used for creating or setting values within tests are unlikely to
- // represent credentials to some accessible system.
- not (
- source.getNode().asExpr().getFile() instanceof TestFile and
- exists(MethodCall createOrAddCall, string createOrAddMethodName |
- createOrAddMethodName.matches("Update%") or
- createOrAddMethodName.matches("Create%") or
- createOrAddMethodName.matches("Add%")
- |
- createOrAddCall.getTarget().hasName(createOrAddMethodName) and
- createOrAddCall.getAnArgument() = sink.getNode().asExpr()
- )
- )
- }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /**
- * A string literal that is not empty.
- */
- class NonEmptyStringLiteral extends Source {
- NonEmptyStringLiteral() { this.getExpr().(StringLiteral).getValue().length() > 1 }
- }
-
- /**
- * The creation of a literal byte array.
- */
- class ByteArrayLiteral extends Source {
- ByteArrayLiteral() {
- this.getExpr() =
- any(ArrayCreation ac |
- ac.getArrayType().getElementType() instanceof ByteType and
- ac.hasInitializer()
- )
- }
- }
-
- /**
- * The creation of a literal char array.
- */
- class CharArrayLiteral extends Source {
- CharArrayLiteral() {
- this.getExpr() =
- any(ArrayCreation ac |
- ac.getArrayType().getElementType() instanceof CharType and
- ac.hasInitializer()
- )
- }
- }
-
- /**
- * An assignable whose name indicates that the value being held is a credential.
- */
- private class CredentialVar extends Assignable {
- pragma[noinline]
- CredentialVar() {
- exists(string name | name = this.getName() |
- name.regexpMatch("(?i).*pass(wd|word|code|phrase)(?!.*question).*")
- or
- name.regexpMatch("(?i).*(puid|username|userid).*")
- or
- name.regexpMatch("(?i).*(cert)(?!.*(format|name)).*")
- )
- }
- }
-
- private class CredentialVariableAccess extends VariableAccess {
- pragma[noinline]
- CredentialVariableAccess() { this.getTarget() instanceof CredentialVar }
- }
-
- /**
- * Gets a credential sink, a display name, the operation it exists in, and a description of the sink.
- */
- private predicate getCredentialSink(
- Expr sink, string sinkName, Element supplementaryElement, string description
- ) {
- // An argument to a library call that looks like a credential
- // "...flows to the [Username] parameter in [call to method CreateUser]"
- exists(Call call, CredentialVar param |
- supplementaryElement = call and
- description = "the $@ parameter in $@" and
- sink = call.getArgumentForParameter(param) and
- sinkName = param.getName() and
- call.getTarget().fromLibrary()
- )
- or
- // An argument to a library setter call for a property that looks like a credential
- // "...flows to the [setter call argument] for the property [UserName]"
- exists(Property p, Call call |
- call = p.getSetter().getACall() and
- supplementaryElement = p and
- description = "the $@ in $@" and
- sink = call.getArgument(0) and
- sinkName = "setter call argument" and
- p instanceof CredentialVar and
- p.fromLibrary()
- )
- or
- // Sink compared to password variable
- // "...flows to [] which is compared against [access of UserName]"
- exists(ComparisonTest ct, CredentialVariableAccess credentialAccess |
- sinkName = sink.toString() and
- supplementaryElement = credentialAccess and
- description = "$@ which is compared against $@" and
- ct.getAnArgument() = credentialAccess and
- ct.getAnArgument() = sink and
- ct.getComparisonKind().isEquality() and
- not sink = credentialAccess
- )
- }
-
- /**
- * An expression that is a sink for a specific type of credential.
- */
- class HardcodedCredentialsSinkExpr extends Sink {
- private string description;
- private Element supplementaryElement;
- private string sinkName;
-
- HardcodedCredentialsSinkExpr() {
- getCredentialSink(this.getExpr(), sinkName, supplementaryElement, description)
- }
-
- override string getSinkDescription() { result = description }
-
- override Element getSupplementaryElement() { result = supplementaryElement }
-
- override string getSinkName() { result = sinkName }
- }
-
- /**
- * A "name" argument to a construction of "MembershipUser" or a subtype.
- */
- class MembershipUserUserNameSink extends Sink {
- private Call call;
-
- MembershipUserUserNameSink() {
- call.getTarget().getDeclaringType().getABaseType*() instanceof
- SystemWebSecurityMembershipUserClass and
- this.getExpr() = call.getArgumentForName("name")
- }
-
- override string getSinkDescription() { result = "the $@ parameter in $@" }
-
- override Element getSupplementaryElement() { result = call }
-
- override string getSinkName() { result = "name" }
- }
-
- /**
- * A "rawData" argument to a construction of "X509Certificate" or a subtype.
- */
- class X509CertificateDataSink extends Sink {
- private ObjectCreation x509Creation;
-
- X509CertificateDataSink() {
- x509Creation.getTarget().getDeclaringType() instanceof
- SystemSecurityCryptographyX509CertificatesX509CertificateClass and
- this.getExpr() = x509Creation.getArgumentForName("rawData")
- }
-
- override string getSinkDescription() { result = "the $@ parameter in $@" }
-
- override Element getSupplementaryElement() { result = x509Creation }
-
- override string getSinkName() { result = "rawData" }
- }
-
- /**
- * A format argument to `Format`, that is considered not to be a source of hardcoded secret data.
- */
- class StringFormatSanitizer extends Sanitizer {
- StringFormatSanitizer() {
- this.getExpr() =
- any(SystemStringClass s).getFormatMethod().getACall().getArgumentForName("format")
- }
- }
-
- /**
- * A replacement argument to `Replace`, that is considered not to be a source of hardcoded secret
- * data.
- */
- class StringReplaceSanitizer extends Sanitizer {
- StringReplaceSanitizer() {
- exists(SystemStringClass s, Call c | c = s.getReplaceMethod().getACall() |
- this.getExpr() = c.getArgumentForName("newValue") or
- this.getExpr() = c.getArgumentForName("newChar")
- )
- }
- }
-
- /**
- * A call to a `ToString()` method, which is considered not to return hard-coded constants.
- */
- class ToStringSanitizer extends Sanitizer {
- ToStringSanitizer() { this.getExpr() = any(Call c | c.getTarget().hasName("ToString")) }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll
new file mode 100644
index 00000000000..68e6a8a6fb0
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll
@@ -0,0 +1,258 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about hard coded credentials.
+ */
+
+import csharp
+private import semmle.code.csharp.commons.ComparisonTest
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.csharp.frameworks.Moq
+private import semmle.code.csharp.frameworks.system.web.Security
+private import semmle.code.csharp.frameworks.system.security.cryptography.X509Certificates
+private import semmle.code.csharp.frameworks.Test
+
+/**
+ * A data flow source for hard coded credentials.
+ */
+abstract class Source extends DataFlow::ExprNode { }
+
+/**
+ * A data flow sink for hard coded credentials.
+ */
+abstract class Sink extends DataFlow::ExprNode {
+ /**
+ * Gets a description of this sink, including a placeholder for the sink and a placeholder for
+ * the supplementary element.
+ */
+ abstract string getSinkDescription();
+
+ /** Gets an element that is used as supplementary data in the description. */
+ abstract Element getSupplementaryElement();
+
+ /** Gets the sink name to use when displaying the sink. */
+ abstract string getSinkName();
+}
+
+/**
+ * A sanitizer for hard coded credentials.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for hard coded credentials.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "HardcodedCredentials" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) {
+ sink instanceof Sink and
+ // Ignore values that are ultimately returned by mocks, as they don't represent "real"
+ // credentials.
+ not any(ReturnedByMockObject mock).getAMemberInitializationValue() = sink.asExpr() and
+ not any(ReturnedByMockObject mock).getAnArgument() = sink.asExpr()
+ }
+
+ override predicate hasFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
+ super.hasFlowPath(source, sink) and
+ // Exclude hard-coded credentials in tests if they only flow to calls to methods with a name
+ // like "Add*" "Create*" or "Update*". The rationale is that hard-coded credentials within
+ // tests that are only used for creating or setting values within tests are unlikely to
+ // represent credentials to some accessible system.
+ not (
+ source.getNode().asExpr().getFile() instanceof TestFile and
+ exists(MethodCall createOrAddCall, string createOrAddMethodName |
+ createOrAddMethodName.matches("Update%") or
+ createOrAddMethodName.matches("Create%") or
+ createOrAddMethodName.matches("Add%")
+ |
+ createOrAddCall.getTarget().hasName(createOrAddMethodName) and
+ createOrAddCall.getAnArgument() = sink.getNode().asExpr()
+ )
+ )
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/**
+ * A string literal that is not empty.
+ */
+class NonEmptyStringLiteral extends Source {
+ NonEmptyStringLiteral() { this.getExpr().(StringLiteral).getValue().length() > 1 }
+}
+
+/**
+ * The creation of a literal byte array.
+ */
+class ByteArrayLiteral extends Source {
+ ByteArrayLiteral() {
+ this.getExpr() =
+ any(ArrayCreation ac |
+ ac.getArrayType().getElementType() instanceof ByteType and
+ ac.hasInitializer()
+ )
+ }
+}
+
+/**
+ * The creation of a literal char array.
+ */
+class CharArrayLiteral extends Source {
+ CharArrayLiteral() {
+ this.getExpr() =
+ any(ArrayCreation ac |
+ ac.getArrayType().getElementType() instanceof CharType and
+ ac.hasInitializer()
+ )
+ }
+}
+
+/**
+ * An assignable whose name indicates that the value being held is a credential.
+ */
+private class CredentialVar extends Assignable {
+ pragma[noinline]
+ CredentialVar() {
+ exists(string name | name = this.getName() |
+ name.regexpMatch("(?i).*pass(wd|word|code|phrase)(?!.*question).*")
+ or
+ name.regexpMatch("(?i).*(puid|username|userid).*")
+ or
+ name.regexpMatch("(?i).*(cert)(?!.*(format|name)).*")
+ )
+ }
+}
+
+private class CredentialVariableAccess extends VariableAccess {
+ pragma[noinline]
+ CredentialVariableAccess() { this.getTarget() instanceof CredentialVar }
+}
+
+/**
+ * Gets a credential sink, a display name, the operation it exists in, and a description of the sink.
+ */
+private predicate getCredentialSink(
+ Expr sink, string sinkName, Element supplementaryElement, string description
+) {
+ // An argument to a library call that looks like a credential
+ // "...flows to the [Username] parameter in [call to method CreateUser]"
+ exists(Call call, CredentialVar param |
+ supplementaryElement = call and
+ description = "the $@ parameter in $@" and
+ sink = call.getArgumentForParameter(param) and
+ sinkName = param.getName() and
+ call.getTarget().fromLibrary()
+ )
+ or
+ // An argument to a library setter call for a property that looks like a credential
+ // "...flows to the [setter call argument] for the property [UserName]"
+ exists(Property p, Call call |
+ call = p.getSetter().getACall() and
+ supplementaryElement = p and
+ description = "the $@ in $@" and
+ sink = call.getArgument(0) and
+ sinkName = "setter call argument" and
+ p instanceof CredentialVar and
+ p.fromLibrary()
+ )
+ or
+ // Sink compared to password variable
+ // "...flows to [] which is compared against [access of UserName]"
+ exists(ComparisonTest ct, CredentialVariableAccess credentialAccess |
+ sinkName = sink.toString() and
+ supplementaryElement = credentialAccess and
+ description = "$@ which is compared against $@" and
+ ct.getAnArgument() = credentialAccess and
+ ct.getAnArgument() = sink and
+ ct.getComparisonKind().isEquality() and
+ not sink = credentialAccess
+ )
+}
+
+/**
+ * An expression that is a sink for a specific type of credential.
+ */
+class HardcodedCredentialsSinkExpr extends Sink {
+ private string description;
+ private Element supplementaryElement;
+ private string sinkName;
+
+ HardcodedCredentialsSinkExpr() {
+ getCredentialSink(this.getExpr(), sinkName, supplementaryElement, description)
+ }
+
+ override string getSinkDescription() { result = description }
+
+ override Element getSupplementaryElement() { result = supplementaryElement }
+
+ override string getSinkName() { result = sinkName }
+}
+
+/**
+ * A "name" argument to a construction of "MembershipUser" or a subtype.
+ */
+class MembershipUserUserNameSink extends Sink {
+ private Call call;
+
+ MembershipUserUserNameSink() {
+ call.getTarget().getDeclaringType().getABaseType*() instanceof
+ SystemWebSecurityMembershipUserClass and
+ this.getExpr() = call.getArgumentForName("name")
+ }
+
+ override string getSinkDescription() { result = "the $@ parameter in $@" }
+
+ override Element getSupplementaryElement() { result = call }
+
+ override string getSinkName() { result = "name" }
+}
+
+/**
+ * A "rawData" argument to a construction of "X509Certificate" or a subtype.
+ */
+class X509CertificateDataSink extends Sink {
+ private ObjectCreation x509Creation;
+
+ X509CertificateDataSink() {
+ x509Creation.getTarget().getDeclaringType() instanceof
+ SystemSecurityCryptographyX509CertificatesX509CertificateClass and
+ this.getExpr() = x509Creation.getArgumentForName("rawData")
+ }
+
+ override string getSinkDescription() { result = "the $@ parameter in $@" }
+
+ override Element getSupplementaryElement() { result = x509Creation }
+
+ override string getSinkName() { result = "rawData" }
+}
+
+/**
+ * A format argument to `Format`, that is considered not to be a source of hardcoded secret data.
+ */
+class StringFormatSanitizer extends Sanitizer {
+ StringFormatSanitizer() {
+ this.getExpr() =
+ any(SystemStringClass s).getFormatMethod().getACall().getArgumentForName("format")
+ }
+}
+
+/**
+ * A replacement argument to `Replace`, that is considered not to be a source of hardcoded secret
+ * data.
+ */
+class StringReplaceSanitizer extends Sanitizer {
+ StringReplaceSanitizer() {
+ exists(SystemStringClass s, Call c | c = s.getReplaceMethod().getACall() |
+ this.getExpr() = c.getArgumentForName("newValue") or
+ this.getExpr() = c.getArgumentForName("newChar")
+ )
+ }
+}
+
+/**
+ * A call to a `ToString()` method, which is considered not to return hard-coded constants.
+ */
+class ToStringSanitizer extends Sanitizer {
+ ToStringSanitizer() { this.getExpr() = any(Call c | c.getTarget().hasName("ToString")) }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjection.qll
deleted file mode 100644
index 50681f9721c..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjection.qll
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about unvalidated user input that is used to
- * construct LDAP queries.
- */
-
-import csharp
-
-module LDAPInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.DirectoryServices
- import semmle.code.csharp.frameworks.system.directoryservices.Protocols
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for unvalidated user input that is used to construct LDAP queries.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for unvalidated user input that is used to construct LDAP queries.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for unvalidated user input that is used to construct LDAP queries.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "LDAPInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP
- * injection.
- *
- * This is either an argument to the constructor, or to the setter for the property.
- */
- class DirectoryEntryPathSink extends Sink {
- DirectoryEntryPathSink() {
- exists(ObjectCreation create |
- create.getTarget() = any(SystemDirectoryServicesDirectoryEntryClass d).getAConstructor()
- |
- this.getExpr() = create.getArgumentForName("path")
- )
- or
- exists(Property path |
- path = any(SystemDirectoryServicesDirectoryEntryClass d).getAProperty() and
- path.hasName("Path")
- |
- this.getExpr() = path.getSetter().getACall().getArgument(0)
- )
- }
- }
-
- /**
- * A argument that sets the `Filter` property of a `DirectorySearcher` object that is a sink for
- * LDAP injection.
- *
- * This is either an argument to the constructor, or to the setter for the property.
- */
- class DirectorySearcherFilterSink extends Sink {
- DirectorySearcherFilterSink() {
- exists(ObjectCreation create |
- create.getTarget() = any(SystemDirectoryServicesDirectorySearcherClass d).getAConstructor()
- |
- this.getExpr() = create.getArgumentForName("filter")
- )
- or
- exists(Property filter |
- filter = any(SystemDirectoryServicesDirectorySearcherClass d).getAProperty() and
- filter.hasName("Filter")
- |
- this.getExpr() = filter.getSetter().getACall().getArgument(0)
- )
- }
- }
-
- /**
- * A argument that sets the `Filter` property of a `SearchRequest` object that is a sink for
- * LDAP injection.
- *
- * This is either an argument to the constructor, or to the setter for the property.
- */
- class SearchRequestFilterSink extends Sink {
- SearchRequestFilterSink() {
- exists(ObjectCreation create |
- create.getTarget() = any(SystemDirectoryServicesProtocolsSearchRequest d).getAConstructor()
- |
- this.getExpr() = create.getArgumentForName("ldapFilter") or
- this.getExpr() = create.getArgumentForName("filter")
- )
- or
- exists(Property filter |
- filter = any(SystemDirectoryServicesProtocolsSearchRequest d).getAProperty() and
- filter.hasName("Filter")
- |
- this.getExpr() = filter.getSetter().getACall().getArgument(0)
- )
- }
- }
-
- /**
- * A call to a method which is named "LDAP*Encode", which is likely to be an LDAP sanitizer.
- *
- * This will match the encoding methods provided by the AntiXSS library.
- */
- class LDAPEncodeSanitizer extends Sanitizer {
- LDAPEncodeSanitizer() {
- this.getExpr().(MethodCall).getTarget().getName().regexpMatch("(?i)LDAP.*Encode.*")
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll
new file mode 100644
index 00000000000..5aa27202f4f
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll
@@ -0,0 +1,128 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about unvalidated user input that is used to
+ * construct LDAP queries.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.DirectoryServices
+private import semmle.code.csharp.frameworks.system.directoryservices.Protocols
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for unvalidated user input that is used to construct LDAP queries.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for unvalidated user input that is used to construct LDAP queries.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for unvalidated user input that is used to construct LDAP queries.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "LDAPInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP
+ * injection.
+ *
+ * This is either an argument to the constructor, or to the setter for the property.
+ */
+class DirectoryEntryPathSink extends Sink {
+ DirectoryEntryPathSink() {
+ exists(ObjectCreation create |
+ create.getTarget() = any(SystemDirectoryServicesDirectoryEntryClass d).getAConstructor()
+ |
+ this.getExpr() = create.getArgumentForName("path")
+ )
+ or
+ exists(Property path |
+ path = any(SystemDirectoryServicesDirectoryEntryClass d).getAProperty() and
+ path.hasName("Path")
+ |
+ this.getExpr() = path.getSetter().getACall().getArgument(0)
+ )
+ }
+}
+
+/**
+ * A argument that sets the `Filter` property of a `DirectorySearcher` object that is a sink for
+ * LDAP injection.
+ *
+ * This is either an argument to the constructor, or to the setter for the property.
+ */
+class DirectorySearcherFilterSink extends Sink {
+ DirectorySearcherFilterSink() {
+ exists(ObjectCreation create |
+ create.getTarget() = any(SystemDirectoryServicesDirectorySearcherClass d).getAConstructor()
+ |
+ this.getExpr() = create.getArgumentForName("filter")
+ )
+ or
+ exists(Property filter |
+ filter = any(SystemDirectoryServicesDirectorySearcherClass d).getAProperty() and
+ filter.hasName("Filter")
+ |
+ this.getExpr() = filter.getSetter().getACall().getArgument(0)
+ )
+ }
+}
+
+/**
+ * A argument that sets the `Filter` property of a `SearchRequest` object that is a sink for
+ * LDAP injection.
+ *
+ * This is either an argument to the constructor, or to the setter for the property.
+ */
+class SearchRequestFilterSink extends Sink {
+ SearchRequestFilterSink() {
+ exists(ObjectCreation create |
+ create.getTarget() = any(SystemDirectoryServicesProtocolsSearchRequest d).getAConstructor()
+ |
+ this.getExpr() = create.getArgumentForName("ldapFilter") or
+ this.getExpr() = create.getArgumentForName("filter")
+ )
+ or
+ exists(Property filter |
+ filter = any(SystemDirectoryServicesProtocolsSearchRequest d).getAProperty() and
+ filter.hasName("Filter")
+ |
+ this.getExpr() = filter.getSetter().getACall().getArgument(0)
+ )
+ }
+}
+
+/**
+ * A call to a method which is named "LDAP*Encode", which is likely to be an LDAP sanitizer.
+ *
+ * This will match the encoding methods provided by the AntiXSS library.
+ */
+class LDAPEncodeSanitizer extends Sanitizer {
+ LDAPEncodeSanitizer() {
+ this.getExpr().(MethodCall).getTarget().getName().regexpMatch("(?i)LDAP.*Encode.*")
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForging.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForging.qll
deleted file mode 100644
index d06fb17e9c4..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForging.qll
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used in log entries.
- */
-
-import csharp
-
-module LogForging {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.System
- import semmle.code.csharp.frameworks.system.text.RegularExpressions
- import semmle.code.csharp.security.Sanitizers
- import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
-
- /**
- * A data flow source for untrusted user input used in log entries.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input used in log entries.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for untrusted user input used in log entries.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input used in log entries.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "LogForging" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- class HtmlSanitizer extends Sanitizer {
- HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }
- }
-
- /**
- * An argument to a call to a method on a logger class.
- */
- class LogForgingLogMessageSink extends Sink, LogMessageSink { }
-
- /**
- * An argument to a call to a method on a trace class.
- */
- class LogForgingTraceMessageSink extends Sink, TraceMessageSink { }
-
- /**
- * A call to String replace or remove that is considered to sanitize replaced string.
- */
- class StringReplaceSanitizer extends Sanitizer {
- StringReplaceSanitizer() {
- exists(Method m |
- exists(SystemStringClass s | m = s.getReplaceMethod() or m = s.getRemoveMethod())
- or
- m = any(SystemTextRegularExpressionsRegexClass r).getAReplaceMethod()
- |
- this.asExpr() = m.getACall()
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForgingQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForgingQuery.qll
new file mode 100644
index 00000000000..9320975c4d5
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/LogForgingQuery.qll
@@ -0,0 +1,76 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used in log entries.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.csharp.frameworks.system.text.RegularExpressions
+private import semmle.code.csharp.security.Sanitizers
+private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
+
+/**
+ * A data flow source for untrusted user input used in log entries.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input used in log entries.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for untrusted user input used in log entries.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used in log entries.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "LogForging" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+private class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+private class HtmlSanitizer extends Sanitizer {
+ HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }
+}
+
+/**
+ * An argument to a call to a method on a logger class.
+ */
+private class LogForgingLogMessageSink extends Sink, LogMessageSink { }
+
+/**
+ * An argument to a call to a method on a trace class.
+ */
+private class LogForgingTraceMessageSink extends Sink, TraceMessageSink { }
+
+/**
+ * A call to String replace or remove that is considered to sanitize replaced string.
+ */
+private class StringReplaceSanitizer extends Sanitizer {
+ StringReplaceSanitizer() {
+ exists(Method m |
+ exists(SystemStringClass s | m = s.getReplaceMethod() or m = s.getRemoveMethod())
+ or
+ m = any(SystemTextRegularExpressionsRegexClass r).getAReplaceMethod()
+ |
+ this.asExpr() = m.getACall()
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidation.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidation.qll
deleted file mode 100644
index ba5ee7147d3..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidation.qll
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input processed as XML
- * without validation against a known schema.
- */
-
-import csharp
-
-module MissingXMLValidation {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.Xml
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input processed as XML without validation against a known
- * schema.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input processed as XML without validation against a known
- * schema.
- */
- abstract class Sink extends DataFlow::ExprNode {
- /** Gets a string describing the reason why this is a sink. */
- abstract string getReason();
- }
-
- /**
- * A sanitizer for untrusted user input processed as XML without validation against a known schema.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input processed as XML without validation against a
- * known schema.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "MissingXMLValidation" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * The input argument to a call to `XmlReader.Create` where the input will not be validated against
- * a schema.
- */
- class XmlReaderCreateCallSink extends Sink {
- XmlReaderCreateCall createCall;
-
- XmlReaderCreateCallSink() {
- // This is the XML that will be processed
- this.getExpr() = createCall.getArgumentForName("input")
- }
-
- override string getReason() {
- // No settings = no Schema validation
- result = "there is no 'XmlReaderSettings' instance specifying schema validation." and
- not exists(createCall.getSettings())
- or
- // An XmlReaderSettings instance is passed where:
- // - The ValidationType is not set to Schema; or
- // - The ValidationType is set to Schema, but:
- // - The ProcessInlineSchema option is set (this allows the document to set a schema
- // internally); or
- // - The ProcessSchemaLocation option is set (this allows the document to reference a
- // schema by location that this document will validate against).
- result = "the 'XmlReaderSettings' instance does not specify the 'ValidationType' as 'Schema'." and
- exists(XmlReaderSettingsCreation settingsCreation |
- settingsCreation = createCall.getSettings().getASettingsCreation()
- |
- not settingsCreation.getValidationType().hasName("Schema")
- )
- or
- exists(string badValidationFlag |
- result = "the 'XmlReaderSettings' instance specifies '" + badValidationFlag + "'." and
- exists(XmlReaderSettingsCreation settingsCreation |
- settingsCreation = createCall.getSettings().getASettingsCreation() and
- settingsCreation.getValidationType().hasName("Schema") and
- settingsCreation.getAValidationFlag().hasName(badValidationFlag)
- |
- badValidationFlag = "ProcessInlineSchema" or
- badValidationFlag = "ProcessSchemaLocation"
- )
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll
new file mode 100644
index 00000000000..e39cf1f0c44
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll
@@ -0,0 +1,97 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input processed as XML
+ * without validation against a known schema.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.Xml
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input processed as XML without validation against a known
+ * schema.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input processed as XML without validation against a known
+ * schema.
+ */
+abstract class Sink extends DataFlow::ExprNode {
+ /** Gets a string describing the reason why this is a sink. */
+ abstract string getReason();
+}
+
+/**
+ * A sanitizer for untrusted user input processed as XML without validation against a known schema.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input processed as XML without validation against a
+ * known schema.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "MissingXMLValidation" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * The input argument to a call to `XmlReader.Create` where the input will not be validated against
+ * a schema.
+ */
+class XmlReaderCreateCallSink extends Sink {
+ XmlReaderCreateCall createCall;
+
+ XmlReaderCreateCallSink() {
+ // This is the XML that will be processed
+ this.getExpr() = createCall.getArgumentForName("input")
+ }
+
+ override string getReason() {
+ // No settings = no Schema validation
+ result = "there is no 'XmlReaderSettings' instance specifying schema validation." and
+ not exists(createCall.getSettings())
+ or
+ // An XmlReaderSettings instance is passed where:
+ // - The ValidationType is not set to Schema; or
+ // - The ValidationType is set to Schema, but:
+ // - The ProcessInlineSchema option is set (this allows the document to set a schema
+ // internally); or
+ // - The ProcessSchemaLocation option is set (this allows the document to reference a
+ // schema by location that this document will validate against).
+ result = "the 'XmlReaderSettings' instance does not specify the 'ValidationType' as 'Schema'." and
+ exists(XmlReaderSettingsCreation settingsCreation |
+ settingsCreation = createCall.getSettings().getASettingsCreation()
+ |
+ not settingsCreation.getValidationType().hasName("Schema")
+ )
+ or
+ exists(string badValidationFlag |
+ result = "the 'XmlReaderSettings' instance specifies '" + badValidationFlag + "'." and
+ exists(XmlReaderSettingsCreation settingsCreation |
+ settingsCreation = createCall.getSettings().getASettingsCreation() and
+ settingsCreation.getValidationType().hasName("Schema") and
+ settingsCreation.getAValidationFlag().hasName(badValidationFlag)
+ |
+ badValidationFlag = "ProcessInlineSchema" or
+ badValidationFlag = "ProcessSchemaLocation"
+ )
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoS.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoS.qll
deleted file mode 100644
index 235793db1c4..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoS.qll
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used in dangerous
- * regular expression operations.
- */
-
-import csharp
-
-module ReDoS {
- private import semmle.code.csharp.dataflow.DataFlow2
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.text.RegularExpressions
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input used in dangerous regular expression operations.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input used in dangerous regular expression operations.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for untrusted user input used in dangerous regular expression operations.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input used in dangerous regular expression operations.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "ReDoS" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * An expression that represents a regular expression with potential exponential behavior.
- */
- predicate isExponentialRegex(StringLiteral s) {
- /*
- * Detect three variants of a common pattern that leads to exponential blow-up.
- */
-
- // Example: ([a-z]+.)+
- s.getValue().regexpMatch(".*\\([^()*+\\]]+\\]?(\\*|\\+)\\.?\\)(\\*|\\+).*")
- or
- // Example: (([a-z])?([a-z]+.))+
- s.getValue()
- .regexpMatch(".*\\((\\([^()]+\\)\\?)?\\([^()*+\\]]+\\]?(\\*|\\+)\\.?\\)\\)(\\*|\\+).*")
- or
- // Example: (([a-z])+.)+
- s.getValue().regexpMatch(".*\\(\\([^()*+\\]]+\\]?\\)(\\*|\\+)\\.?\\)(\\*|\\+).*")
- }
-
- /**
- * A data flow configuration for tracking exponential worst case time regular expression string
- * literals to the pattern argument of a regex.
- */
- class ExponentialRegexDataflow extends DataFlow2::Configuration {
- ExponentialRegexDataflow() { this = "ExponentialRegex" }
-
- override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
-
- override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
- }
-
- /**
- * An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
- * have exponential behaviour.
- */
- class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
- ExponentialRegexSink() {
- exists(ExponentialRegexDataflow regexDataflow, RegexOperation regexOperation |
- // Exponential regex flows to the pattern argument
- regexDataflow.hasFlow(_, DataFlow::exprNode(regexOperation.getPattern()))
- |
- // This is used as an input for this pattern
- this.getExpr() = regexOperation.getInput() and
- // No timeouts
- not regexOperation.hasTimeout()
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoSQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoSQuery.qll
new file mode 100644
index 00000000000..79ad4ec1a40
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ReDoSQuery.qll
@@ -0,0 +1,96 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used in dangerous
+ * regular expression operations.
+ */
+
+import csharp
+private import semmle.code.csharp.dataflow.DataFlow2
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.text.RegularExpressions
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input used in dangerous regular expression operations.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input used in dangerous regular expression operations.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for untrusted user input used in dangerous regular expression operations.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used in dangerous regular expression operations.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "ReDoS" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * An expression that represents a regular expression with potential exponential behavior.
+ */
+predicate isExponentialRegex(StringLiteral s) {
+ /*
+ * Detect three variants of a common pattern that leads to exponential blow-up.
+ */
+
+ // Example: ([a-z]+.)+
+ s.getValue().regexpMatch(".*\\([^()*+\\]]+\\]?(\\*|\\+)\\.?\\)(\\*|\\+).*")
+ or
+ // Example: (([a-z])?([a-z]+.))+
+ s.getValue()
+ .regexpMatch(".*\\((\\([^()]+\\)\\?)?\\([^()*+\\]]+\\]?(\\*|\\+)\\.?\\)\\)(\\*|\\+).*")
+ or
+ // Example: (([a-z])+.)+
+ s.getValue().regexpMatch(".*\\(\\([^()*+\\]]+\\]?\\)(\\*|\\+)\\.?\\)(\\*|\\+).*")
+}
+
+/**
+ * A data flow configuration for tracking exponential worst case time regular expression string
+ * literals to the pattern argument of a regex.
+ */
+class ExponentialRegexDataflow extends DataFlow2::Configuration {
+ ExponentialRegexDataflow() { this = "ExponentialRegex" }
+
+ override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
+
+ override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
+}
+
+/**
+ * An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
+ * have exponential behaviour.
+ */
+class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
+ ExponentialRegexSink() {
+ exists(ExponentialRegexDataflow regexDataflow, RegexOperation regexOperation |
+ // Exponential regex flows to the pattern argument
+ regexDataflow.hasFlow(_, DataFlow::exprNode(regexOperation.getPattern()))
+ |
+ // This is used as an input for this pattern
+ this.getExpr() = regexOperation.getInput() and
+ // No timeouts
+ not regexOperation.hasTimeout()
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjection.qll
deleted file mode 100644
index 2edfbc4ab7c..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjection.qll
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used to construct
- * regular expressions.
- */
-
-import csharp
-
-module RegexInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.text.RegularExpressions
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input used to construct regular expressions.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input used to construct regular expressions.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for untrusted user input used to construct regular expressions.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input used to construct regular expressions.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "RegexInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * A `pattern` argument to a construction of a `Regex`.
- */
- class RegexObjectCreationSink extends Sink {
- RegexObjectCreationSink() {
- exists(RegexOperation operation |
- this.getExpr() = operation.getPattern() and
- not operation.hasTimeout()
- )
- }
- }
-
- /** A call to `Regex.Escape` that sanitizes the user input for use in a regex. */
- class RegexEscapeSanitizer extends Sanitizer {
- RegexEscapeSanitizer() {
- this.getExpr().(MethodCall).getTarget() =
- any(SystemTextRegularExpressionsRegexClass r).getAMethod("Escape")
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll
new file mode 100644
index 00000000000..7631375eba5
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll
@@ -0,0 +1,66 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used to construct
+ * regular expressions.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.text.RegularExpressions
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input used to construct regular expressions.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input used to construct regular expressions.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for untrusted user input used to construct regular expressions.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used to construct regular expressions.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "RegexInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * A `pattern` argument to a construction of a `Regex`.
+ */
+class RegexObjectCreationSink extends Sink {
+ RegexObjectCreationSink() {
+ exists(RegexOperation operation |
+ this.getExpr() = operation.getPattern() and
+ not operation.hasTimeout()
+ )
+ }
+}
+
+/** A call to `Regex.Escape` that sanitizes the user input for use in a regex. */
+class RegexEscapeSanitizer extends Sanitizer {
+ RegexEscapeSanitizer() {
+ this.getExpr().(MethodCall).getTarget() =
+ any(SystemTextRegularExpressionsRegexClass r).getAMethod("Escape")
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjection.qll
deleted file mode 100644
index 236fe62aa2c..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjection.qll
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used in resource descriptors.
- */
-
-import csharp
-
-module ResourceInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.security.dataflow.flowsources.Local
- import semmle.code.csharp.frameworks.system.Data
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input used in resource descriptors.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input used in resource descriptors.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for untrusted user input used in resource descriptors.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input used in resource descriptors.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "ResourceInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** A source of local user input. */
- class LocalSource extends Source {
- LocalSource() { this instanceof LocalFlowSource }
- }
-
- /** An argument to the `ConnectionString` property on a data connection class. */
- class SqlConnectionStringSink extends Sink {
- SqlConnectionStringSink() {
- this.getExpr() =
- any(SystemDataConnectionClass dataConn).getConnectionStringProperty().getAnAssignedValue()
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll
new file mode 100644
index 00000000000..cfcdd93aaa3
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll
@@ -0,0 +1,59 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used in resource descriptors.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.security.dataflow.flowsources.Local
+private import semmle.code.csharp.frameworks.system.Data
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input used in resource descriptors.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input used in resource descriptors.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for untrusted user input used in resource descriptors.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used in resource descriptors.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "ResourceInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** A source of local user input. */
+class LocalSource extends Source {
+ LocalSource() { this instanceof LocalFlowSource }
+}
+
+/** An argument to the `ConnectionString` property on a data connection class. */
+class SqlConnectionStringSink extends Sink {
+ SqlConnectionStringSink() {
+ this.getExpr() =
+ any(SystemDataConnectionClass dataConn).getConnectionStringProperty().getAnAssignedValue()
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjection.qll
deleted file mode 100644
index 21c2628aa62..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjection.qll
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about SQL injection vulnerabilities.
- */
-
-import csharp
-
-module SqlInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.security.dataflow.flowsources.Local
- import semmle.code.csharp.frameworks.Sql
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A source specific to SQL injection vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A sink for SQL injection vulnerabilities.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for SQL injection vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for SQL injection vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "SqlInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** A source of local user input. */
- class LocalSource extends Source {
- LocalSource() { this instanceof LocalFlowSource }
- }
-
- /** An SQL expression passed to an API call that executes SQL. */
- class SqlInjectionExprSink extends Sink {
- SqlInjectionExprSink() { exists(SqlExpr s | this.getExpr() = s.getSql()) }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll
new file mode 100644
index 00000000000..37b2d7fd7c3
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll
@@ -0,0 +1,56 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about SQL injection vulnerabilities.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.security.dataflow.flowsources.Local
+private import semmle.code.csharp.frameworks.Sql
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A source specific to SQL injection vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A sink for SQL injection vulnerabilities.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for SQL injection vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for SQL injection vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "SqlInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** A source of local user input. */
+class LocalSource extends Source {
+ LocalSource() { this instanceof LocalFlowSource }
+}
+
+/** An SQL expression passed to an API call that executes SQL. */
+class SqlInjectionExprSink extends Sink {
+ SqlInjectionExprSink() { exists(SqlExpr s | this.getExpr() = s.getSql()) }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll
deleted file mode 100644
index 0772305c7c1..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about uncontrolled data in path expression
- * vulnerabilities.
- */
-
-import csharp
-
-module TaintedPath {
- import semmle.code.csharp.controlflow.Guards
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.IO
- import semmle.code.csharp.frameworks.system.Web
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for uncontrolled data in path expression vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for uncontrolled data in path expression vulnerabilities.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for uncontrolled data in path expression vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "TaintedPath" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * A path argument to a `File` method call.
- */
- class FileCreateSink extends Sink {
- FileCreateSink() {
- exists(Method create | create = any(SystemIOFileClass f).getAMethod() |
- this.getExpr() = create.getACall().getArgumentForName("path")
- )
- }
- }
-
- /**
- * A path argument to a `Directory` method call.
- */
- class DirectorySink extends Sink {
- DirectorySink() {
- exists(Method create | create = any(SystemIODirectoryClass f).getAMethod() |
- this.getExpr() = create.getACall().getArgumentForName("path")
- )
- }
- }
-
- /**
- * A path argument to a `FileStream` constructor call.
- */
- class FileStreamSink extends Sink {
- FileStreamSink() {
- exists(ObjectCreation oc |
- oc.getTarget().getDeclaringType() = any(SystemIOFileStreamClass f)
- |
- this.getExpr() = oc.getArgumentForName("path")
- )
- }
- }
-
- /**
- * A path argument to a `StreamWriter` constructor call.
- */
- class StreamWriterTaintedPathSink extends Sink {
- StreamWriterTaintedPathSink() {
- exists(ObjectCreation oc |
- oc.getTarget().getDeclaringType() = any(SystemIOStreamWriterClass f)
- |
- this.getExpr() = oc.getArgumentForName("path")
- )
- }
- }
-
- /**
- * A weak guard that is insufficient to prevent path tampering.
- */
- private class WeakGuard extends Guard {
- WeakGuard() {
- // None of these are sufficient to guarantee that a string is safe.
- exists(MethodCall mc, Method m | this = mc and mc.getTarget() = m |
- m.getName() = "StartsWith" or
- m.getName() = "EndsWith" or
- m.getName() = "IsNullOrEmpty" or
- m.getName() = "IsNullOrWhitespace" or
- m = any(SystemIOFileClass f).getAMethod("Exists") or
- m = any(SystemIODirectoryClass f).getAMethod("Exists")
- )
- or
- // Checking against `null` has no bearing on path traversal.
- this.controlsNode(_, _, any(AbstractValues::NullValue nv))
- or
- this.(LogicalOperation).getAnOperand() instanceof WeakGuard
- }
- }
-
- /**
- * A conditional involving the path, that is not considered to be a weak check.
- *
- * A weak check is one that is insufficient to prevent path tampering.
- */
- class PathCheck extends Sanitizer {
- PathCheck() {
- // This expression is structurally replicated in a dominating guard which is not a "weak" check
- exists(Guard g, AbstractValues::BooleanValue v |
- g = this.(GuardedDataFlowNode).getAGuard(_, v) and
- not g instanceof WeakGuard
- )
- }
- }
-
- /**
- * A call to `HttpRequest.MapPath` that is considered to sanitize the input.
- */
- class RequestMapPathSanitizer extends Sanitizer {
- RequestMapPathSanitizer() {
- exists(Method m |
- m = any(SystemWebHttpRequestClass request).getAMethod() and
- m.hasName("MapPath")
- |
- this.getExpr() = m.getACall()
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPathQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPathQuery.qll
new file mode 100644
index 00000000000..0379173578e
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPathQuery.qll
@@ -0,0 +1,145 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about uncontrolled data in path expression
+ * vulnerabilities.
+ */
+
+import csharp
+private import semmle.code.csharp.controlflow.Guards
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.IO
+private import semmle.code.csharp.frameworks.system.Web
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for uncontrolled data in path expression vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for uncontrolled data in path expression vulnerabilities.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for uncontrolled data in path expression vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "TaintedPath" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * A path argument to a `File` method call.
+ */
+class FileCreateSink extends Sink {
+ FileCreateSink() {
+ exists(Method create | create = any(SystemIOFileClass f).getAMethod() |
+ this.getExpr() = create.getACall().getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A path argument to a `Directory` method call.
+ */
+class DirectorySink extends Sink {
+ DirectorySink() {
+ exists(Method create | create = any(SystemIODirectoryClass f).getAMethod() |
+ this.getExpr() = create.getACall().getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A path argument to a `FileStream` constructor call.
+ */
+class FileStreamSink extends Sink {
+ FileStreamSink() {
+ exists(ObjectCreation oc | oc.getTarget().getDeclaringType() = any(SystemIOFileStreamClass f) |
+ this.getExpr() = oc.getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A path argument to a `StreamWriter` constructor call.
+ */
+class StreamWriterTaintedPathSink extends Sink {
+ StreamWriterTaintedPathSink() {
+ exists(ObjectCreation oc |
+ oc.getTarget().getDeclaringType() = any(SystemIOStreamWriterClass f)
+ |
+ this.getExpr() = oc.getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A weak guard that is insufficient to prevent path tampering.
+ */
+private class WeakGuard extends Guard {
+ WeakGuard() {
+ // None of these are sufficient to guarantee that a string is safe.
+ exists(MethodCall mc, Method m | this = mc and mc.getTarget() = m |
+ m.getName() = "StartsWith" or
+ m.getName() = "EndsWith" or
+ m.getName() = "IsNullOrEmpty" or
+ m.getName() = "IsNullOrWhitespace" or
+ m = any(SystemIOFileClass f).getAMethod("Exists") or
+ m = any(SystemIODirectoryClass f).getAMethod("Exists")
+ )
+ or
+ // Checking against `null` has no bearing on path traversal.
+ this.controlsNode(_, _, any(AbstractValues::NullValue nv))
+ or
+ this.(LogicalOperation).getAnOperand() instanceof WeakGuard
+ }
+}
+
+/**
+ * A conditional involving the path, that is not considered to be a weak check.
+ *
+ * A weak check is one that is insufficient to prevent path tampering.
+ */
+class PathCheck extends Sanitizer {
+ PathCheck() {
+ // This expression is structurally replicated in a dominating guard which is not a "weak" check
+ exists(Guard g, AbstractValues::BooleanValue v |
+ g = this.(GuardedDataFlowNode).getAGuard(_, v) and
+ not g instanceof WeakGuard
+ )
+ }
+}
+
+/**
+ * A call to `HttpRequest.MapPath` that is considered to sanitize the input.
+ */
+class RequestMapPathSanitizer extends Sanitizer {
+ RequestMapPathSanitizer() {
+ exists(Method m |
+ m = any(SystemWebHttpRequestClass request).getAMethod() and
+ m.hasName("MapPath")
+ |
+ this.getExpr() = m.getACall()
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
deleted file mode 100644
index 0943774d8cd..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about uncontrolled data
- * in calls to unsafe deserializers (XML, JSON, XAML).
- */
-
-import csharp
-
-module UnsafeDeserialization {
- private import semmle.code.csharp.security.dataflow.flowsources.Remote
- private import semmle.code.csharp.serialization.Deserializers
-
- /**
- * A data flow source for unsafe deserialization vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for unsafe deserialization vulnerabilities.
- */
- abstract class Sink extends DataFlow::Node { }
-
- /**
- * A sanitizer for unsafe deserialization vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::Node { }
-
- /**
- * A taint-tracking configuration for reasoning about unsafe deserialization.
- */
- class TaintTrackingConfig extends TaintTracking::Configuration {
- TaintTrackingConfig() { this = "UnsafeDeserialization" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** A call to an unsafe deserializer. */
- class UnsafeDeserializerSink extends Sink {
- UnsafeDeserializerSink() {
- exists(Call c |
- this.asExpr() = c.getAnArgument() and
- c.getTarget() instanceof UnsafeDeserializer
- )
- }
- }
-
- private class JavaScriptSerializerClass extends Class {
- JavaScriptSerializerClass() {
- this.hasQualifiedName("System.Web.Script.Serialization.JavaScriptSerializer")
- }
- }
-
- /**
- * An unsafe use of a JavaScript deserializer. That is, a use with a custom type-resolver
- * (constructor parameter).
- */
- class JavaScriptSerializerSink extends Sink {
- JavaScriptSerializerSink() {
- exists(ObjectCreation oc |
- oc.getTarget().getDeclaringType() instanceof JavaScriptSerializerClass and
- oc.getTarget().getNumberOfParameters() > 0 and
- exists(MethodCall mc, Method m |
- m = mc.getTarget() and
- m.getDeclaringType() instanceof JavaScriptSerializerClass and
- (
- m.hasName("Deserialize") or
- m.hasName("DeserializeObject")
- ) and
- this.asExpr() = mc.getAnArgument() and
- DataFlow::localFlow(DataFlow::exprNode(oc), DataFlow::exprNode(mc.getQualifier()))
- )
- )
- }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll
new file mode 100644
index 00000000000..7d710575ce2
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll
@@ -0,0 +1,79 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about uncontrolled data
+ * in calls to unsafe deserializers (XML, JSON, XAML).
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.serialization.Deserializers
+
+/**
+ * A data flow source for unsafe deserialization vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for unsafe deserialization vulnerabilities.
+ */
+abstract class Sink extends DataFlow::Node { }
+
+/**
+ * A sanitizer for unsafe deserialization vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::Node { }
+
+/**
+ * A taint-tracking configuration for reasoning about unsafe deserialization.
+ */
+class TaintTrackingConfig extends TaintTracking::Configuration {
+ TaintTrackingConfig() { this = "UnsafeDeserialization" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+private class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** A call to an unsafe deserializer. */
+private class UnsafeDeserializerSink extends Sink {
+ UnsafeDeserializerSink() {
+ exists(Call c |
+ this.asExpr() = c.getAnArgument() and
+ c.getTarget() instanceof UnsafeDeserializer
+ )
+ }
+}
+
+private class JavaScriptSerializerClass extends Class {
+ JavaScriptSerializerClass() {
+ this.hasQualifiedName("System.Web.Script.Serialization.JavaScriptSerializer")
+ }
+}
+
+/**
+ * An unsafe use of a JavaScript deserializer. That is, a use with a custom type-resolver
+ * (constructor parameter).
+ */
+private class JavaScriptSerializerSink extends Sink {
+ JavaScriptSerializerSink() {
+ exists(ObjectCreation oc |
+ oc.getTarget().getDeclaringType() instanceof JavaScriptSerializerClass and
+ oc.getTarget().getNumberOfParameters() > 0 and
+ exists(MethodCall mc, Method m |
+ m = mc.getTarget() and
+ m.getDeclaringType() instanceof JavaScriptSerializerClass and
+ (
+ m.hasName("Deserialize") or
+ m.hasName("DeserializeObject")
+ ) and
+ this.asExpr() = mc.getAnArgument() and
+ DataFlow::localFlow(DataFlow::exprNode(oc), DataFlow::exprNode(mc.getQualifier()))
+ )
+ )
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll
deleted file mode 100644
index 2008e62c60d..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about unvalidated URL redirect problems.
- */
-
-import csharp
-
-module UrlRedirect {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.controlflow.Guards
- import semmle.code.csharp.frameworks.system.Web
- import semmle.code.csharp.frameworks.system.web.Mvc
- import semmle.code.csharp.security.Sanitizers
- import semmle.code.csharp.frameworks.microsoft.AspNetCore
-
- /**
- * A data flow source for unvalidated URL redirect vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for unvalidated URL redirect vulnerabilities.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for unvalidated URL redirect vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A guard for unvalidated URL redirect vulnerabilities.
- */
- abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
-
- /**
- * A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "UrlRedirect" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
-
- override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
- guard instanceof SanitizerGuard
- }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
- * sink for URL redirects.
- */
- class RedirectSink extends Sink {
- RedirectSink() {
- exists(MethodCall mc |
- mc.getTarget() = any(SystemWebHttpResponseClass response).getRedirectMethod() or
- mc.getTarget() = any(SystemWebMvcControllerClass response).getARedirectMethod()
- |
- // Redirect uses the parameter name url
- this.getExpr() = mc.getArgumentForName("url")
- or
- // RedirectToAction
- this.getExpr() = mc.getArgumentForName("actionName")
- or
- // RedirectToRoute
- this.getExpr() = mc.getArgumentForName("routeName")
- )
- }
- }
-
- /**
- * A value argument to a call to `AddHeader` or `AppendHeader` that adds the `Location`.
- */
- class LocationHeaderSink extends Sink {
- LocationHeaderSink() {
- exists(MethodCall call |
- call.getTarget() = any(SystemWebHttpResponseClass r).getAppendHeaderMethod() or
- call.getTarget() = any(SystemWebHttpResponseClass r).getAddHeaderMethod()
- |
- call.getArgumentForName("name").getValue() = "Location" and
- this.getExpr() = call.getArgumentForName("value")
- )
- }
- }
-
- /**
- * A path argument to a call to `HttpServerUtility.Transfer`.
- */
- class HttpServerTransferSink extends Sink {
- HttpServerTransferSink() {
- exists(MethodCall call |
- call.getTarget() = any(SystemWebHttpServerUtility s).getTransferMethod()
- |
- this.getExpr() = call.getArgumentForName("path")
- )
- }
- }
-
- /**
- * A URL argument to a call to `UrlHelper.isLocalUrl()` that is a sanitizer for URL redirects.
- */
- class IsLocalUrlSanitizer extends SanitizerGuard, MethodCall {
- IsLocalUrlSanitizer() { this.getTarget().hasName("IsLocalUrl") }
-
- override predicate checks(Expr e, AbstractValue v) {
- e = this.getArgument(0) and
- v.(AbstractValues::BooleanValue).getValue() = true
- }
- }
-
- /**
- * A call to the getter of the RawUrl property, whose value is considered to be safe for URL
- * redirects.
- */
- class RawUrlSanitizer extends Sanitizer {
- RawUrlSanitizer() {
- this.getExpr() = any(SystemWebHttpRequestClass r).getRawUrlProperty().getGetter().getACall()
- }
- }
-
- /**
- * A string concatenation expression, where the left hand side contains the character "?".
- *
- * This is considered as sanitizing the overall expression, because the attacker can then
- * only control the query string parameters, rather than the location itself. In the majority of
- * cases, this will only allow the attacker to redirect the user to a link they could have already
- * redirected them to.
- */
- class ConcatenationSanitizer extends Sanitizer {
- ConcatenationSanitizer() {
- this.getType() instanceof StringType and
- this.getExpr().(AddExpr).getLeftOperand().getValue().matches("%?%")
- }
- }
-
- /** A call to an URL encoder. */
- class UrlEncodeSanitizer extends Sanitizer {
- UrlEncodeSanitizer() { this.getExpr() instanceof UrlSanitizedExpr }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-
- /**
- * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
- * sink for URL redirects.
- */
- class AspNetCoreRedirectSink extends Sink {
- AspNetCoreRedirectSink() {
- exists(MethodCall mc |
- mc.getTarget() = any(MicrosoftAspNetCoreHttpHttpResponse response).getRedirectMethod() or
- mc.getTarget() = any(MicrosoftAspNetCoreMvcController response).getARedirectMethod()
- |
- // Response.Redirect uses 'location' parameter
- this.getExpr() = mc.getArgumentForName("location")
- or
- // Redirect uses the parameter name 'url'
- this.getExpr() = mc.getArgumentForName("url")
- or
- // Controller.RedirectToAction*
- this.getExpr() = mc.getArgumentForName("actionName")
- or
- // Controller.RedirectToRoute*
- this.getExpr() = mc.getArgumentForName("routeName")
- or
- // Controller.RedirectToPage*
- this.getExpr() = mc.getArgumentForName("pageName")
- )
- }
- }
-
- /**
- * Anything that is setting "location" header in the response headers.
- */
- class AspNetCoreLocationHeaderSink extends Sink {
- AspNetCoreLocationHeaderSink() {
- // ResponseHeaders.Location =
- exists(AssignableDefinition def |
- def.getTarget() = any(MicrosoftAspNetCoreHttpResponseHeaders headers).getLocationProperty()
- |
- this.asExpr() = def.getSource()
- )
- or
- // HttpResponse.Headers.Append("location", )
- exists(MethodCall mc, MicrosoftAspNetCoreHttpHeaderDictionaryExtensions ext |
- mc.getTarget() = ext.getAppendMethod() or
- mc.getTarget() = ext.getAppendCommaSeparatedValuesMethod() or
- mc.getTarget() = ext.getSetCommaSeparatedValuesMethod()
- |
- mc.getArgumentForName("key").getValue().toLowerCase() = "location" and
- this.getExpr() = mc.getArgument(2)
- )
- or
- // HttpResponse.Headers.Add("location", )
- exists(
- RefType cl, MicrosoftAspNetCoreHttpHttpResponse resp, PropertyAccess qualifier,
- MethodCall add
- |
- qualifier.getTarget() = resp.getHeadersProperty() and
- add.getTarget() = cl.getAMethod("Add") and
- qualifier = add.getQualifier() and
- add.getArgument(0).getValue().toLowerCase() = "location" and
- this.getExpr() = add.getArgument(1)
- )
- or
- // HttpResponse.Headers["location"] =
- exists(
- RefType cl, MicrosoftAspNetCoreHttpHttpResponse resp, IndexerAccess ci, Call cs,
- PropertyAccess qualifier
- |
- qualifier.getTarget() = resp.getHeadersProperty() and
- ci.getTarget() = cl.getAnIndexer() and
- qualifier = ci.getQualifier() and
- cs.getTarget() = cl.getAnIndexer().getSetter() and
- cs.getArgument(0).getValue().toLowerCase() = "location" and
- this.asExpr() = cs.getArgument(1)
- )
- }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll
new file mode 100644
index 00000000000..067c2788070
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll
@@ -0,0 +1,225 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about unvalidated URL redirect problems.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.controlflow.Guards
+private import semmle.code.csharp.frameworks.system.Web
+private import semmle.code.csharp.frameworks.system.web.Mvc
+private import semmle.code.csharp.security.Sanitizers
+private import semmle.code.csharp.frameworks.microsoft.AspNetCore
+
+/**
+ * A data flow source for unvalidated URL redirect vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for unvalidated URL redirect vulnerabilities.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for unvalidated URL redirect vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A guard for unvalidated URL redirect vulnerabilities.
+ */
+abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
+
+/**
+ * A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "UrlRedirect" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+
+ override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
+ guard instanceof SanitizerGuard
+ }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
+ * sink for URL redirects.
+ */
+class RedirectSink extends Sink {
+ RedirectSink() {
+ exists(MethodCall mc |
+ mc.getTarget() = any(SystemWebHttpResponseClass response).getRedirectMethod() or
+ mc.getTarget() = any(SystemWebMvcControllerClass response).getARedirectMethod()
+ |
+ // Redirect uses the parameter name url
+ this.getExpr() = mc.getArgumentForName("url")
+ or
+ // RedirectToAction
+ this.getExpr() = mc.getArgumentForName("actionName")
+ or
+ // RedirectToRoute
+ this.getExpr() = mc.getArgumentForName("routeName")
+ )
+ }
+}
+
+/**
+ * A value argument to a call to `AddHeader` or `AppendHeader` that adds the `Location`.
+ */
+class LocationHeaderSink extends Sink {
+ LocationHeaderSink() {
+ exists(MethodCall call |
+ call.getTarget() = any(SystemWebHttpResponseClass r).getAppendHeaderMethod() or
+ call.getTarget() = any(SystemWebHttpResponseClass r).getAddHeaderMethod()
+ |
+ call.getArgumentForName("name").getValue() = "Location" and
+ this.getExpr() = call.getArgumentForName("value")
+ )
+ }
+}
+
+/**
+ * A path argument to a call to `HttpServerUtility.Transfer`.
+ */
+class HttpServerTransferSink extends Sink {
+ HttpServerTransferSink() {
+ exists(MethodCall call |
+ call.getTarget() = any(SystemWebHttpServerUtility s).getTransferMethod()
+ |
+ this.getExpr() = call.getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A URL argument to a call to `UrlHelper.isLocalUrl()` that is a sanitizer for URL redirects.
+ */
+class IsLocalUrlSanitizer extends SanitizerGuard, MethodCall {
+ IsLocalUrlSanitizer() { this.getTarget().hasName("IsLocalUrl") }
+
+ override predicate checks(Expr e, AbstractValue v) {
+ e = this.getArgument(0) and
+ v.(AbstractValues::BooleanValue).getValue() = true
+ }
+}
+
+/**
+ * A call to the getter of the RawUrl property, whose value is considered to be safe for URL
+ * redirects.
+ */
+class RawUrlSanitizer extends Sanitizer {
+ RawUrlSanitizer() {
+ this.getExpr() = any(SystemWebHttpRequestClass r).getRawUrlProperty().getGetter().getACall()
+ }
+}
+
+/**
+ * A string concatenation expression, where the left hand side contains the character "?".
+ *
+ * This is considered as sanitizing the overall expression, because the attacker can then
+ * only control the query string parameters, rather than the location itself. In the majority of
+ * cases, this will only allow the attacker to redirect the user to a link they could have already
+ * redirected them to.
+ */
+class ConcatenationSanitizer extends Sanitizer {
+ ConcatenationSanitizer() {
+ this.getType() instanceof StringType and
+ this.getExpr().(AddExpr).getLeftOperand().getValue().matches("%?%")
+ }
+}
+
+/** A call to an URL encoder. */
+class UrlEncodeSanitizer extends Sanitizer {
+ UrlEncodeSanitizer() { this.getExpr() instanceof UrlSanitizedExpr }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
+
+/**
+ * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
+ * sink for URL redirects.
+ */
+class AspNetCoreRedirectSink extends Sink {
+ AspNetCoreRedirectSink() {
+ exists(MethodCall mc |
+ mc.getTarget() = any(MicrosoftAspNetCoreHttpHttpResponse response).getRedirectMethod() or
+ mc.getTarget() = any(MicrosoftAspNetCoreMvcController response).getARedirectMethod()
+ |
+ // Response.Redirect uses 'location' parameter
+ this.getExpr() = mc.getArgumentForName("location")
+ or
+ // Redirect uses the parameter name 'url'
+ this.getExpr() = mc.getArgumentForName("url")
+ or
+ // Controller.RedirectToAction*
+ this.getExpr() = mc.getArgumentForName("actionName")
+ or
+ // Controller.RedirectToRoute*
+ this.getExpr() = mc.getArgumentForName("routeName")
+ or
+ // Controller.RedirectToPage*
+ this.getExpr() = mc.getArgumentForName("pageName")
+ )
+ }
+}
+
+/**
+ * Anything that is setting "location" header in the response headers.
+ */
+class AspNetCoreLocationHeaderSink extends Sink {
+ AspNetCoreLocationHeaderSink() {
+ // ResponseHeaders.Location =
+ exists(AssignableDefinition def |
+ def.getTarget() = any(MicrosoftAspNetCoreHttpResponseHeaders headers).getLocationProperty()
+ |
+ this.asExpr() = def.getSource()
+ )
+ or
+ // HttpResponse.Headers.Append("location", )
+ exists(MethodCall mc, MicrosoftAspNetCoreHttpHeaderDictionaryExtensions ext |
+ mc.getTarget() = ext.getAppendMethod() or
+ mc.getTarget() = ext.getAppendCommaSeparatedValuesMethod() or
+ mc.getTarget() = ext.getSetCommaSeparatedValuesMethod()
+ |
+ mc.getArgumentForName("key").getValue().toLowerCase() = "location" and
+ this.getExpr() = mc.getArgument(2)
+ )
+ or
+ // HttpResponse.Headers.Add("location", )
+ exists(
+ RefType cl, MicrosoftAspNetCoreHttpHttpResponse resp, PropertyAccess qualifier, MethodCall add
+ |
+ qualifier.getTarget() = resp.getHeadersProperty() and
+ add.getTarget() = cl.getAMethod("Add") and
+ qualifier = add.getQualifier() and
+ add.getArgument(0).getValue().toLowerCase() = "location" and
+ this.getExpr() = add.getArgument(1)
+ )
+ or
+ // HttpResponse.Headers["location"] =
+ exists(
+ RefType cl, MicrosoftAspNetCoreHttpHttpResponse resp, IndexerAccess ci, Call cs,
+ PropertyAccess qualifier
+ |
+ qualifier.getTarget() = resp.getHeadersProperty() and
+ ci.getTarget() = cl.getAnIndexer() and
+ qualifier = ci.getQualifier() and
+ cs.getTarget() = cl.getAnIndexer().getSetter() and
+ cs.getArgument(0).getValue().toLowerCase() = "location" and
+ this.asExpr() = cs.getArgument(1)
+ )
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjection.qll
deleted file mode 100644
index 425fd6b4019..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjection.qll
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used in XML processing
- */
-
-import csharp
-
-module XMLEntityInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.System
- import semmle.code.csharp.frameworks.system.text.RegularExpressions
- import semmle.code.csharp.security.xml.InsecureXML
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input used in XML processing.
- */
- abstract class Source extends DataFlow::Node { }
-
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /**
- * A data flow sink for untrusted user input used in XML processing.
- */
- abstract class Sink extends DataFlow::ExprNode {
- /**
- * Gets the reason for the insecurity of this sink.
- */
- abstract string getReason();
- }
-
- class InsecureXMLSink extends Sink {
- private string reason;
-
- InsecureXMLSink() {
- exists(InsecureXML::InsecureXmlProcessing r | r.isUnsafe(reason) |
- this.getExpr() = r.getAnArgument()
- )
- }
-
- override string getReason() { result = reason }
- }
-
- /**
- * A sanitizer for untrusted user input used in XML processing.
- */
- abstract class Sanitizer extends DataFlow::Node { }
-
- /**
- * A taint-tracking configuration for untrusted user input used in XML processing.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "XMLInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
-
- override predicate hasFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
- super.hasFlowPath(source, sink) and
- exists(sink.getNode().(Sink).getReason())
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjectionQuery.qll
new file mode 100644
index 00000000000..cf27d2db49b
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XMLEntityInjectionQuery.qll
@@ -0,0 +1,68 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used in XML processing
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.System
+private import semmle.code.csharp.frameworks.system.text.RegularExpressions
+private import semmle.code.csharp.security.xml.InsecureXMLQuery as InsecureXML
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input used in XML processing.
+ */
+abstract class Source extends DataFlow::Node { }
+
+private class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/**
+ * A data flow sink for untrusted user input used in XML processing.
+ */
+abstract class Sink extends DataFlow::ExprNode {
+ /**
+ * Gets the reason for the insecurity of this sink.
+ */
+ abstract string getReason();
+}
+
+private class InsecureXMLSink extends Sink {
+ private string reason;
+
+ InsecureXMLSink() {
+ exists(InsecureXML::InsecureXmlProcessing r | r.isUnsafe(reason) |
+ this.getExpr() = r.getAnArgument()
+ )
+ }
+
+ override string getReason() { result = reason }
+}
+
+/**
+ * A sanitizer for untrusted user input used in XML processing.
+ */
+abstract class Sanitizer extends DataFlow::Node { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used in XML processing.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "XMLInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+
+ override predicate hasFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
+ super.hasFlowPath(source, sink) and
+ exists(sink.getNode().(Sink).getReason())
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjection.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjection.qll
deleted file mode 100644
index 7c84561cf44..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjection.qll
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about untrusted user input used in XPath expression.
- */
-
-import csharp
-
-module XPathInjection {
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- import semmle.code.csharp.frameworks.system.xml.XPath
- import semmle.code.csharp.frameworks.system.Xml
- import semmle.code.csharp.security.Sanitizers
-
- /**
- * A data flow source for untrusted user input used in XPath expression.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for untrusted user input used in XPath expression.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for untrusted user input used in XPath expression.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for untrusted user input used in XPath expression.
- */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "XPathInjection" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- /** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
- class XPathExpressionCompileSink extends Sink {
- XPathExpressionCompileSink() {
- this.getExpr() =
- any(SystemXmlXPath::XPathExpression xpathExpr)
- .getAMethod("Compile")
- .getACall()
- .getArgumentForName("xpath")
- }
- }
-
- /** The `xpath` argument to an `XmlNode.Select*Node*(..)` call. */
- class XmlNodeSink extends Sink {
- XmlNodeSink() {
- this.getExpr() =
- any(SystemXmlXmlNodeClass xmlNode)
- .getASelectNodeMethod()
- .getACall()
- .getArgumentForName("xpath")
- }
- }
-
- /** The `xpath` argument to an `XPathNavigator` call. */
- class XmlNavigatorSink extends Sink {
- XmlNavigatorSink() {
- exists(SystemXmlXPath::XPathNavigator xmlNav, Method m |
- this.getExpr() = m.getACall().getArgumentForName("xpath")
- |
- m = xmlNav.getASelectMethod() or
- m = xmlNav.getCompileMethod() or
- m = xmlNav.getAnEvaluateMethod() or
- m = xmlNav.getAMatchesMethod()
- )
- }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjectionQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjectionQuery.qll
new file mode 100644
index 00000000000..7b062288f9c
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XPathInjectionQuery.qll
@@ -0,0 +1,82 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about untrusted user input used in XPath expression.
+ */
+
+import csharp
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.frameworks.system.xml.XPath
+private import semmle.code.csharp.frameworks.system.Xml
+private import semmle.code.csharp.security.Sanitizers
+
+/**
+ * A data flow source for untrusted user input used in XPath expression.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for untrusted user input used in XPath expression.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for untrusted user input used in XPath expression.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for untrusted user input used in XPath expression.
+ */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "XPathInjection" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+/** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
+class XPathExpressionCompileSink extends Sink {
+ XPathExpressionCompileSink() {
+ this.getExpr() =
+ any(SystemXmlXPath::XPathExpression xpathExpr)
+ .getAMethod("Compile")
+ .getACall()
+ .getArgumentForName("xpath")
+ }
+}
+
+/** The `xpath` argument to an `XmlNode.Select*Node*(..)` call. */
+class XmlNodeSink extends Sink {
+ XmlNodeSink() {
+ this.getExpr() =
+ any(SystemXmlXmlNodeClass xmlNode)
+ .getASelectNodeMethod()
+ .getACall()
+ .getArgumentForName("xpath")
+ }
+}
+
+/** The `xpath` argument to an `XPathNavigator` call. */
+class XmlNavigatorSink extends Sink {
+ XmlNavigatorSink() {
+ exists(SystemXmlXPath::XPathNavigator xmlNav, Method m |
+ this.getExpr() = m.getACall().getArgumentForName("xpath")
+ |
+ m = xmlNav.getASelectMethod() or
+ m = xmlNav.getCompileMethod() or
+ m = xmlNav.getAnEvaluateMethod() or
+ m = xmlNav.getAMatchesMethod()
+ )
+ }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll
deleted file mode 100644
index 763fb46a4f1..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll
+++ /dev/null
@@ -1,423 +0,0 @@
-/**
- * Provides a taint-tracking configuration for reasoning about cross-site scripting
- * (XSS) vulnerabilities.
- */
-
-import csharp
-
-module XSS {
- import semmle.code.asp.AspNet
- import semmle.code.csharp.frameworks.system.Net
- import semmle.code.csharp.frameworks.system.Web
- import semmle.code.csharp.frameworks.system.web.UI
- import semmle.code.csharp.security.Sanitizers
- import semmle.code.csharp.security.dataflow.flowsinks.Html
- import semmle.code.csharp.security.dataflow.flowsinks.Remote
- import semmle.code.csharp.security.dataflow.flowsources.Remote
- private import semmle.code.csharp.dataflow.DataFlow2
- private import semmle.code.csharp.dataflow.TaintTracking2
-
- /**
- * Holds if there is tainted flow from `source` to `sink` that may lead to a
- * cross-site scripting (XSS) vulnerability, with `message`
- * providing a description of the source.
- * This is the main predicate to use in XSS queries.
- */
- predicate xssFlow(XssNode source, XssNode sink, string message) {
- // standard taint-tracking
- exists(
- TaintTrackingConfiguration c, DataFlow2::PathNode sourceNode, DataFlow2::PathNode sinkNode
- |
- sourceNode = source.asDataFlowNode() and
- sinkNode = sink.asDataFlowNode() and
- c.hasFlowPath(sourceNode, sinkNode) and
- message =
- "is written to HTML or JavaScript" +
- any(string explanation |
- if exists(sinkNode.getNode().(Sink).explanation())
- then explanation = ": " + sinkNode.getNode().(Sink).explanation() + "."
- else explanation = "."
- )
- )
- or
- // flow entirely within ASP inline code
- source = sink and
- source.asAspInlineMember().getMember() instanceof AspNetQueryStringMember and
- message = "is a remote source accessed inline in an ASPX page."
- }
-
- module PathGraph {
- query predicate edges(XssNode pred, XssNode succ) {
- exists(DataFlow2::PathNode a, DataFlow2::PathNode b | DataFlow2::PathGraph::edges(a, b) |
- pred.asDataFlowNode() = a and
- succ.asDataFlowNode() = b
- )
- or
- xssFlow(pred, succ, _) and
- pred instanceof XssAspNode
- }
- }
-
- private newtype TXssNode =
- TXssDataFlowNode(DataFlow2::PathNode node) or
- TXssAspNode(AspInlineMember m)
-
- /**
- * A flow node for tracking cross-site scripting (XSS) vulnerabilities.
- * Can be a standard data flow node (`XssDataFlowNode`)
- * or an ASP inline code element (`XssAspNode`).
- */
- class XssNode extends TXssNode {
- /** Gets a textual representation of this node. */
- string toString() { none() }
-
- /** Gets the location of this node. */
- Location getLocation() { none() }
-
- /** Gets the data flow node corresponding to this node, if any. */
- DataFlow2::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() }
-
- /** Gets the ASP inline code element corresponding to this node, if any. */
- AspInlineMember asAspInlineMember() { result = this.(XssAspNode).getAspInlineMember() }
- }
-
- /** A data flow node, viewed as an XSS flow node. */
- class XssDataFlowNode extends TXssDataFlowNode, XssNode {
- DataFlow2::PathNode node;
-
- XssDataFlowNode() { this = TXssDataFlowNode(node) }
-
- /** Gets the data flow node corresponding to this node. */
- DataFlow2::PathNode getDataFlowNode() { result = node }
-
- override string toString() { result = node.toString() }
-
- override Location getLocation() { result = node.getNode().getLocation() }
- }
-
- /** An ASP inline code element, viewed as an XSS flow node. */
- class XssAspNode extends TXssAspNode, XssNode {
- AspInlineMember member;
-
- XssAspNode() { this = TXssAspNode(member) }
-
- /** Gets the ASP inline code element corresponding to this node. */
- AspInlineMember getAspInlineMember() { result = member }
-
- override string toString() { result = member.toString() }
-
- override Location getLocation() { result = member.getLocation() }
- }
-
- /**
- * A data flow sink for cross-site scripting (XSS) vulnerabilities.
- *
- * Any XSS sink is also a remote flow sink, so this class contributes
- * to the abstract class `RemoteFlowSink`.
- */
- abstract class Sink extends DataFlow::ExprNode, RemoteFlowSink {
- string explanation() { none() }
- }
-
- /**
- * A data flow source for cross-site scripting (XSS) vulnerabilities.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A sanitizer for cross-site scripting (XSS) vulnerabilities.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A taint-tracking configuration for cross-site scripting (XSS) vulnerabilities.
- */
- class TaintTrackingConfiguration extends TaintTracking2::Configuration {
- TaintTrackingConfiguration() { this = "XSSDataFlowConfiguration" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
- }
-
- /** A source of remote user input. */
- class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
- }
-
- private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
-
- private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
-
- /** A call to an HTML encoder. */
- private class HtmlEncodeSanitizer extends Sanitizer {
- HtmlEncodeSanitizer() { this.getExpr() instanceof HtmlSanitizedExpr }
- }
-
- /**
- * A call to a URL encoder.
- *
- * Url encoding is sufficient to sanitize for XSS because it ensures <, >, " and ' are escaped.
- * Furthermore, URL encoding is the only valid way to sanitize URLs that get inserted into HTML
- * attributes. Other uses of URL encoding may or may not produce the desired visual result, but
- * should be safe from XSS.
- */
- private class UrlEncodeSanitizer extends Sanitizer {
- UrlEncodeSanitizer() { this.getExpr() instanceof UrlSanitizedExpr }
- }
-
- private class HtmlSinkSink extends Sink {
- HtmlSinkSink() { this instanceof HtmlSink }
-
- override string explanation() {
- this instanceof WebPageWriteLiteralSink and
- result = "System.Web.WebPages.WebPage.WriteLiteral() method"
- or
- this instanceof WebPageWriteLiteralToSink and
- result = "System.Web.WebPages.WebPage.WriteLiteralTo() method"
- or
- this instanceof MicrosoftAspNetCoreMvcHtmlHelperRawSink and
- result = "Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method"
- or
- this instanceof MicrosoftAspNetRazorPageWriteLiteralSink and
- result = "Microsoft.AspNetCore.Mvc.Razor.RazorPageBase.WriteLiteral() method"
- }
- }
-
- /**
- * An expression that is used as an argument to an XSS sink method on
- * `System.Web.UI.Page`.
- */
- private class PageSink extends Sink {
- PageSink() {
- exists(Property p, SystemWebUIPageClass page |
- p = page.getIDProperty() or
- p = page.getMetaDescriptionProperty() or
- p = page.getMetaKeywordsProperty() or
- p = page.getTitleProperty()
- |
- this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument()
- )
- or
- exists(Method m, SystemWebUIPageClass page |
- m = page.getRegisterStartupScriptMethod() or
- m = page.getRegisterClientScriptBlockMethod()
- |
- this.getExpr() = m.getAParameter().getAnAssignedArgument()
- )
- }
- }
-
- /**
- * An expression that is used as an argument to an XSS sink method on
- * `ClientScriptManager`.
- */
- private class ClientScriptManagerSink extends Sink {
- ClientScriptManagerSink() {
- exists(Method m, SystemWebUIClientScriptManagerClass clientScriptManager, int paramNumber |
- this.getExpr() = m.getParameter(paramNumber).getAnAssignedArgument() and
- (
- paramNumber = 2 and m.getNumberOfParameters() in [3 .. 4]
- or
- paramNumber = 3 and m.getNumberOfParameters() = 5
- )
- |
- m = clientScriptManager.getRegisterClientScriptBlockMethod() or
- m = clientScriptManager.getRegisterStartupScriptMethod()
- )
- }
- }
-
- /**
- * An expression that is used as an argument to an XSS sink setter, on
- * a class within the `System.Web.UI` namespace.
- */
- private class SystemWebSetterNonHtmlSink extends Sink {
- SystemWebSetterNonHtmlSink() {
- exists(Property p, string name |
- any(SystemWebUINamespace n).getAChildNamespace*() = p.getDeclaringType().getNamespace() and
- this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument() and
- p.hasName(name)
- |
- name = "GroupingTest" or
- name = "GroupName" or
- name = "Style" or
- name.matches("%URL")
- )
- }
- }
-
- /**
- * A call to `Parse` for a numeric type, that causes the data to be considered
- * sanitized.
- */
- private class NumericTypeParse extends Sanitizer {
- NumericTypeParse() {
- exists(Method m |
- m.getDeclaringType() instanceof IntegralType or
- m.getDeclaringType() instanceof FloatingPointType
- |
- m.hasName("Parse") and
- this.getExpr().(Call).getTarget() = m
- )
- }
- }
-
- /**
- * Gets a member which is accessed by the given `AspInlineCode`.
- * The code body must consist only of an access to the member, possibly with qualified
- * field accesses or array indexing.
- */
- private Member aspxInlineAccess(AspInlineCode code) {
- result = max(int i, Member m | m = getMemberAccessByIndex(code, i) | m order by i)
- }
-
- /**
- * Gets the `i`th member accessed by `code`, where the string in `code`
- * must be of the form `f1.f2...fn`, `f1.f2...fn[...]`, `f1.f2...fn()`, or
- * `f1.f2...fn[...]()`. The `i`th member is `fi` in all cases.
- */
- private Member getMemberAccessByIndex(AspInlineCode code, int i) {
- exists(ValueOrRefType t |
- result.getName() = getMemberAccessNameByIndex(code, i) and
- t.hasMember(result)
- |
- // Base case: a member on the code-behind class
- i = 0 and
- t = code.getLocation().getFile().(CodeBehindFile).getInheritedType()
- or
- // Recursive case: a nested member
- exists(Member mid |
- mid = getMemberAccessByIndex(code, i - 1) and
- t = getMemberType(mid)
- )
- )
- }
-
- /**
- * Gets the name of the `i`th member accessed by `code`, where the string in `code`
- * must be of the form `f1.f2...fn`, `f1.f2...fn[...]`, `f1.f2...fn()`, or
- * `f1.f2...fn[...]()`. The `i`th member is `fi` in all cases.
- */
- private string getMemberAccessNameByIndex(AspInlineCode code, int i) {
- // Strip:
- // - leading and trailing whitespace, which apparently you're allowed to have
- // - trailing parens, so we can recognize nullary method calls
- // - trailing square brackets with some contents, to recognize indexing into arrays
- result = code.getBody().splitAt(".", i).regexpCapture("\\s*(.*?)(\\[.*\\])?(\\(\\))?\\s*", 1)
- }
-
- /**
- * An `AspInlineCode` which is an access to a member inherited from the
- * corresponding 'CodeBehind' class. This includes direct accesses as well as
- * qualified accesses or array indexing on the member.
- */
- class AspInlineMember extends AspInlineCode {
- Member member;
-
- AspInlineMember() { member = aspxInlineAccess(this) }
-
- /** Gets the member that this inline code references. */
- Member getMember() { result = member }
-
- Type getType() { result = getMemberType(getMember()) }
- }
-
- /** Gets a value that is written to the member accessed by the given `AspInlineMember`. */
- Expr aspWrittenValue(AspInlineMember m) {
- exists(Property p | p = m.getMember() |
- // a directly assigned property
- result = p.getAnAssignedValue()
- or
- // one step of flow through a variable returned by the getter
- // this is mainly to handle trivial forwarding properties
- exists(VariableAccess access |
- p.getGetter().canReturn(access) and
- result = access.getTarget().getAnAssignedValue()
- )
- )
- or
- result = m.getMember().(Field).getAnAssignedValue()
- or
- m.getMember().(Callable).canReturn(result)
- }
-
- private string makeUrl(Location l) {
- exists(string path, int sl, int sc, int el, int ec |
- l.hasLocationInfo(path, sl, sc, el, ec) and
- result = "file://" + path + ":" + sl + ":" + sc + ":" + el + ":" + ec
- )
- }
-
- /**
- * A sink for writes to properties that are accessed in ASP pages.
- *
- * Currently we only support inline code tags that directly reference a member
- * on the corresponding 'CodeBehind' class.
- * This may include qualified accesses to fields or array indexing on the member.
- * The sink is any assigned value of such a
- * member, since we don't track the flow all the way to the ASP element.
- */
- private class AspxCodeSink extends Sink {
- /** The ASP inline code element that references a member of the backing class. */
- AspInlineMember inline;
-
- AspxCodeSink() { this.getExpr() = aspWrittenValue(inline) }
-
- override string explanation() {
- result =
- "member is [[\"accessed inline\"|\"" + makeUrl(inline.getLocation()) +
- "\"]] in an ASPX page"
- }
- }
-
- /** A sink for the output stream associated with a `HttpListenerResponse`. */
- private class HttpListenerResponseSink extends Sink {
- HttpListenerResponseSink() {
- exists(PropertyAccess responseOutputStream |
- responseOutputStream.getProperty() =
- any(SystemNetHttpListenerResponseClass h).getOutputStreamProperty()
- |
- DataFlow::localFlow(DataFlow::exprNode(responseOutputStream), this)
- )
- }
- }
-
- /**
- * An expression that is used as an argument to an XSS sink method on
- * `HttpResponseBase`.
- */
- private class HttpResponseBaseSink extends Sink {
- HttpResponseBaseSink() {
- exists(Method m, SystemWebHttpResponseBaseClass responseClass |
- m = responseClass.getAWriteMethod() or
- m = responseClass.getAWriteFileMethod() or
- m = responseClass.getATransmitFileMethod() or
- m = responseClass.getABinaryWriteMethod()
- |
- // Calls to these methods, or overrides of them
- this.getExpr() = m.getAnOverrider*().getParameter(0).getAnAssignedArgument()
- )
- }
- }
-
- /**
- * An expression passed as the `content` argument to the constructor of `StringContent`.
- */
- private class StringContent extends Sink {
- StringContent() {
- this.getExpr() =
- any(ObjectCreation oc |
- oc.getTarget().getDeclaringType().hasQualifiedName("System.Net.Http", "StringContent")
- ).getArgumentForName("content")
- }
- }
-}
-
-private Type getMemberType(Member m) {
- result = m.(Property).getType() or
- result = m.(Field).getType() or
- result = m.(Callable).getReturnType()
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSQuery.qll
new file mode 100644
index 00000000000..c4b2e0e8f16
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSQuery.qll
@@ -0,0 +1,172 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about cross-site scripting
+ * (XSS) vulnerabilities.
+ */
+
+import csharp
+private import XSSSinks
+private import semmle.code.csharp.security.Sanitizers
+private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.dataflow.DataFlow2
+private import semmle.code.csharp.dataflow.TaintTracking2
+
+/**
+ * Holds if there is tainted flow from `source` to `sink` that may lead to a
+ * cross-site scripting (XSS) vulnerability, with `message`
+ * providing a description of the source.
+ * This is the main predicate to use in XSS queries.
+ */
+predicate xssFlow(XssNode source, XssNode sink, string message) {
+ // standard taint-tracking
+ exists(
+ TaintTrackingConfiguration c, DataFlow2::PathNode sourceNode, DataFlow2::PathNode sinkNode
+ |
+ sourceNode = source.asDataFlowNode() and
+ sinkNode = sink.asDataFlowNode() and
+ c.hasFlowPath(sourceNode, sinkNode) and
+ message =
+ "is written to HTML or JavaScript" +
+ any(string explanation |
+ if exists(sinkNode.getNode().(Sink).explanation())
+ then explanation = ": " + sinkNode.getNode().(Sink).explanation() + "."
+ else explanation = "."
+ )
+ )
+ or
+ // flow entirely within ASP inline code
+ source = sink and
+ source.asAspInlineMember().getMember() instanceof AspNetQueryStringMember and
+ message = "is a remote source accessed inline in an ASPX page."
+}
+
+/**
+ * Provides the query predicates needed to include a graph in a path-problem query.
+ */
+module PathGraph {
+ /** Holds if `(pred,succ)` is an edge in the graph of data flow path explanations. */
+ query predicate edges(XssNode pred, XssNode succ) {
+ exists(DataFlow2::PathNode a, DataFlow2::PathNode b | DataFlow2::PathGraph::edges(a, b) |
+ pred.asDataFlowNode() = a and
+ succ.asDataFlowNode() = b
+ )
+ or
+ xssFlow(pred, succ, _) and
+ pred instanceof XssAspNode
+ }
+}
+
+private newtype TXssNode =
+ TXssDataFlowNode(DataFlow2::PathNode node) or
+ TXssAspNode(AspInlineMember m)
+
+/**
+ * A flow node for tracking cross-site scripting (XSS) vulnerabilities.
+ * Can be a standard data flow node (`XssDataFlowNode`)
+ * or an ASP inline code element (`XssAspNode`).
+ */
+class XssNode extends TXssNode {
+ /** Gets a textual representation of this node. */
+ string toString() { none() }
+
+ /** Gets the location of this node. */
+ Location getLocation() { none() }
+
+ /** Gets the data flow node corresponding to this node, if any. */
+ DataFlow2::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() }
+
+ /** Gets the ASP inline code element corresponding to this node, if any. */
+ AspInlineMember asAspInlineMember() { result = this.(XssAspNode).getAspInlineMember() }
+}
+
+/** A data flow node, viewed as an XSS flow node. */
+class XssDataFlowNode extends TXssDataFlowNode, XssNode {
+ DataFlow2::PathNode node;
+
+ XssDataFlowNode() { this = TXssDataFlowNode(node) }
+
+ /** Gets the data flow node corresponding to this node. */
+ DataFlow2::PathNode getDataFlowNode() { result = node }
+
+ override string toString() { result = node.toString() }
+
+ override Location getLocation() { result = node.getNode().getLocation() }
+}
+
+/** An ASP inline code element, viewed as an XSS flow node. */
+class XssAspNode extends TXssAspNode, XssNode {
+ AspInlineMember member;
+
+ XssAspNode() { this = TXssAspNode(member) }
+
+ /** Gets the ASP inline code element corresponding to this node. */
+ AspInlineMember getAspInlineMember() { result = member }
+
+ override string toString() { result = member.toString() }
+
+ override Location getLocation() { result = member.getLocation() }
+}
+
+/**
+ * A data flow source for cross-site scripting (XSS) vulnerabilities.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A sanitizer for cross-site scripting (XSS) vulnerabilities.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A taint-tracking configuration for cross-site scripting (XSS) vulnerabilities.
+ */
+class TaintTrackingConfiguration extends TaintTracking2::Configuration {
+ TaintTrackingConfiguration() { this = "XSSDataFlowConfiguration" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+}
+
+/** A source of remote user input. */
+private class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+}
+
+private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
+
+private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
+
+/** A call to an HTML encoder. */
+private class HtmlEncodeSanitizer extends Sanitizer {
+ HtmlEncodeSanitizer() { this.getExpr() instanceof HtmlSanitizedExpr }
+}
+
+/**
+ * A call to a URL encoder.
+ *
+ * Url encoding is sufficient to sanitize for XSS because it ensures <, >, " and ' are escaped.
+ * Furthermore, URL encoding is the only valid way to sanitize URLs that get inserted into HTML
+ * attributes. Other uses of URL encoding may or may not produce the desired visual result, but
+ * should be safe from XSS.
+ */
+private class UrlEncodeSanitizer extends Sanitizer {
+ UrlEncodeSanitizer() { this.getExpr() instanceof UrlSanitizedExpr }
+}
+
+/**
+ * A call to `Parse` for a numeric type, that causes the data to be considered
+ * sanitized.
+ */
+private class NumericTypeParse extends Sanitizer {
+ NumericTypeParse() {
+ exists(Method m |
+ m.getDeclaringType() instanceof IntegralType or
+ m.getDeclaringType() instanceof FloatingPointType
+ |
+ m.hasName("Parse") and
+ this.getExpr().(Call).getTarget() = m
+ )
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSSinks.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSSinks.qll
new file mode 100644
index 00000000000..3d3858d974a
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSSSinks.qll
@@ -0,0 +1,261 @@
+/**
+ * Provides sink definitions for cross-site scripting (XSS) vulnerabilities.
+ */
+
+import csharp
+private import semmle.code.asp.AspNet
+private import semmle.code.csharp.frameworks.system.Net
+private import semmle.code.csharp.frameworks.system.Web
+private import semmle.code.csharp.frameworks.system.web.UI
+private import semmle.code.csharp.security.dataflow.flowsinks.Html
+private import semmle.code.csharp.security.dataflow.flowsinks.Remote
+private import semmle.code.csharp.dataflow.ExternalFlow
+
+/**
+ * A data flow sink for cross-site scripting (XSS) vulnerabilities.
+ *
+ * Any XSS sink is also a remote flow sink, so this class contributes
+ * to the abstract class `RemoteFlowSink`.
+ */
+abstract class Sink extends DataFlow::ExprNode, RemoteFlowSink {
+ /** Gets an explanation of this XSS sink. */
+ string explanation() { none() }
+}
+
+private class ExternalXssSink extends Sink {
+ ExternalXssSink() { sinkNode(this, "xss") }
+}
+
+private class HtmlSinkSink extends Sink {
+ HtmlSinkSink() { this instanceof HtmlSink }
+
+ override string explanation() {
+ this instanceof WebPageWriteLiteralSink and
+ result = "System.Web.WebPages.WebPage.WriteLiteral() method"
+ or
+ this instanceof WebPageWriteLiteralToSink and
+ result = "System.Web.WebPages.WebPage.WriteLiteralTo() method"
+ or
+ this instanceof MicrosoftAspNetCoreMvcHtmlHelperRawSink and
+ result = "Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method"
+ or
+ this instanceof MicrosoftAspNetRazorPageWriteLiteralSink and
+ result = "Microsoft.AspNetCore.Mvc.Razor.RazorPageBase.WriteLiteral() method"
+ }
+}
+
+/**
+ * An expression that is used as an argument to an XSS sink method on
+ * `System.Web.UI.Page`.
+ */
+private class PageSink extends Sink {
+ PageSink() {
+ exists(Property p, SystemWebUIPageClass page |
+ p = page.getIDProperty() or
+ p = page.getMetaDescriptionProperty() or
+ p = page.getMetaKeywordsProperty() or
+ p = page.getTitleProperty()
+ |
+ this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument()
+ )
+ or
+ exists(Method m, SystemWebUIPageClass page |
+ m = page.getRegisterStartupScriptMethod() or
+ m = page.getRegisterClientScriptBlockMethod()
+ |
+ this.getExpr() = m.getAParameter().getAnAssignedArgument()
+ )
+ }
+}
+
+/**
+ * An expression that is used as an argument to an XSS sink method on
+ * `ClientScriptManager`.
+ */
+private class ClientScriptManagerSink extends Sink {
+ ClientScriptManagerSink() {
+ exists(Method m, SystemWebUIClientScriptManagerClass clientScriptManager, int paramNumber |
+ this.getExpr() = m.getParameter(paramNumber).getAnAssignedArgument() and
+ (
+ paramNumber = 2 and m.getNumberOfParameters() in [3 .. 4]
+ or
+ paramNumber = 3 and m.getNumberOfParameters() = 5
+ )
+ |
+ m = clientScriptManager.getRegisterClientScriptBlockMethod() or
+ m = clientScriptManager.getRegisterStartupScriptMethod()
+ )
+ }
+}
+
+/**
+ * An expression that is used as an argument to an XSS sink setter, on
+ * a class within the `System.Web.UI` namespace.
+ */
+private class SystemWebSetterNonHtmlSink extends Sink {
+ SystemWebSetterNonHtmlSink() {
+ exists(Property p, string name |
+ any(SystemWebUINamespace n).getAChildNamespace*() = p.getDeclaringType().getNamespace() and
+ this.getExpr() = p.getSetter().getParameter(0).getAnAssignedArgument() and
+ p.hasName(name)
+ |
+ name = "GroupingTest" or
+ name = "GroupName" or
+ name = "Style" or
+ name.matches("%URL")
+ )
+ }
+}
+
+/**
+ * Gets a member which is accessed by the given `AspInlineCode`.
+ * The code body must consist only of an access to the member, possibly with qualified
+ * field accesses or array indexing.
+ */
+private Member aspxInlineAccess(AspInlineCode code) {
+ result = max(int i, Member m | m = getMemberAccessByIndex(code, i) | m order by i)
+}
+
+/**
+ * Gets the `i`th member accessed by `code`, where the string in `code`
+ * must be of the form `f1.f2...fn`, `f1.f2...fn[...]`, `f1.f2...fn()`, or
+ * `f1.f2...fn[...]()`. The `i`th member is `fi` in all cases.
+ */
+private Member getMemberAccessByIndex(AspInlineCode code, int i) {
+ exists(ValueOrRefType t |
+ result.getName() = getMemberAccessNameByIndex(code, i) and
+ t.hasMember(result)
+ |
+ // Base case: a member on the code-behind class
+ i = 0 and
+ t = code.getLocation().getFile().(CodeBehindFile).getInheritedType()
+ or
+ // Recursive case: a nested member
+ exists(Member mid |
+ mid = getMemberAccessByIndex(code, i - 1) and
+ t = getMemberType(mid)
+ )
+ )
+}
+
+/**
+ * Gets the name of the `i`th member accessed by `code`, where the string in `code`
+ * must be of the form `f1.f2...fn`, `f1.f2...fn[...]`, `f1.f2...fn()`, or
+ * `f1.f2...fn[...]()`. The `i`th member is `fi` in all cases.
+ */
+private string getMemberAccessNameByIndex(AspInlineCode code, int i) {
+ // Strip:
+ // - leading and trailing whitespace, which apparently you're allowed to have
+ // - trailing parens, so we can recognize nullary method calls
+ // - trailing square brackets with some contents, to recognize indexing into arrays
+ result = code.getBody().splitAt(".", i).regexpCapture("\\s*(.*?)(\\[.*\\])?(\\(\\))?\\s*", 1)
+}
+
+/**
+ * An `AspInlineCode` which is an access to a member inherited from the
+ * corresponding 'CodeBehind' class. This includes direct accesses as well as
+ * qualified accesses or array indexing on the member.
+ */
+class AspInlineMember extends AspInlineCode {
+ Member member;
+
+ AspInlineMember() { member = aspxInlineAccess(this) }
+
+ /** Gets the member that this inline code references. */
+ Member getMember() { result = member }
+
+ /** Gets the type of this member. */
+ Type getType() { result = getMemberType(getMember()) }
+}
+
+/** Gets a value that is written to the member accessed by the given `AspInlineMember`. */
+private Expr aspWrittenValue(AspInlineMember m) {
+ exists(Property p | p = m.getMember() |
+ // a directly assigned property
+ result = p.getAnAssignedValue()
+ or
+ // one step of flow through a variable returned by the getter
+ // this is mainly to handle trivial forwarding properties
+ exists(VariableAccess access |
+ p.getGetter().canReturn(access) and
+ result = access.getTarget().getAnAssignedValue()
+ )
+ )
+ or
+ result = m.getMember().(Field).getAnAssignedValue()
+ or
+ m.getMember().(Callable).canReturn(result)
+}
+
+private string makeUrl(Location l) {
+ exists(string path, int sl, int sc, int el, int ec |
+ l.hasLocationInfo(path, sl, sc, el, ec) and
+ result = "file://" + path + ":" + sl + ":" + sc + ":" + el + ":" + ec
+ )
+}
+
+/**
+ * A sink for writes to properties that are accessed in ASP pages.
+ *
+ * Currently we only support inline code tags that directly reference a member
+ * on the corresponding 'CodeBehind' class.
+ * This may include qualified accesses to fields or array indexing on the member.
+ * The sink is any assigned value of such a
+ * member, since we don't track the flow all the way to the ASP element.
+ */
+private class AspxCodeSink extends Sink {
+ /** The ASP inline code element that references a member of the backing class. */
+ AspInlineMember inline;
+
+ AspxCodeSink() { this.getExpr() = aspWrittenValue(inline) }
+
+ override string explanation() {
+ result =
+ "member is [[\"accessed inline\"|\"" + makeUrl(inline.getLocation()) + "\"]] in an ASPX page"
+ }
+}
+
+/** A sink for the output stream associated with a `HttpListenerResponse`. */
+private class HttpListenerResponseSink extends Sink {
+ HttpListenerResponseSink() {
+ exists(PropertyAccess responseOutputStream |
+ responseOutputStream.getProperty() =
+ any(SystemNetHttpListenerResponseClass h).getOutputStreamProperty()
+ |
+ DataFlow::localFlow(DataFlow::exprNode(responseOutputStream), this)
+ )
+ }
+}
+
+/**
+ * An expression that is used as an argument to an XSS sink method on
+ * `HttpResponseBase`.
+ */
+private class HttpResponseBaseSink extends Sink {
+ HttpResponseBaseSink() {
+ exists(Method m, SystemWebHttpResponseBaseClass responseClass |
+ m = responseClass.getAWriteMethod() or
+ m = responseClass.getAWriteFileMethod() or
+ m = responseClass.getATransmitFileMethod() or
+ m = responseClass.getABinaryWriteMethod()
+ |
+ // Calls to these methods, or overrides of them
+ this.getExpr() = m.getAnOverrider*().getParameter(0).getAnAssignedArgument()
+ )
+ }
+}
+
+/**
+ * An expression passed as the `content` argument to the constructor of `StringContent`.
+ */
+private class StringContentSinkModelCsv extends SinkModelCsv {
+ override predicate row(string row) {
+ row = ["System.Net.Http;StringContent;false;StringContent;;;Argument[0];xss"]
+ }
+}
+
+private Type getMemberType(Member m) {
+ result = m.(Property).getType() or
+ result = m.(Field).getType() or
+ result = m.(Callable).getReturnType()
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll
deleted file mode 100644
index c2785173be4..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Provides a taint tracking configuration for reasoning about unsafe zip extraction.
- */
-
-import csharp
-
-module ZipSlip {
- import semmle.code.csharp.controlflow.Guards
-
- /**
- * A data flow source for unsafe zip extraction.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for unsafe zip extraction.
- */
- abstract class Sink extends DataFlow::ExprNode { }
-
- /**
- * A sanitizer for unsafe zip extraction.
- */
- abstract class Sanitizer extends DataFlow::ExprNode { }
-
- /**
- * A guard for unsafe zip extraction.
- */
- abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
-
- /** A taint tracking configuration for Zip Slip */
- class TaintTrackingConfiguration extends TaintTracking::Configuration {
- TaintTrackingConfiguration() { this = "ZipSlipTaintTracking" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
-
- override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
- guard instanceof SanitizerGuard
- }
- }
-
- /** An access to the `FullName` property of a `ZipArchiveEntry`. */
- class ArchiveFullNameSource extends Source {
- ArchiveFullNameSource() {
- exists(PropertyAccess pa | this.asExpr() = pa |
- pa.getTarget().getDeclaringType().hasQualifiedName("System.IO.Compression.ZipArchiveEntry") and
- pa.getTarget().getName() = "FullName"
- )
- }
- }
-
- /** An argument to the `ExtractToFile` extension method. */
- class ExtractToFileArgSink extends Sink {
- ExtractToFileArgSink() {
- exists(MethodCall mc |
- mc.getTarget().hasQualifiedName("System.IO.Compression.ZipFileExtensions", "ExtractToFile") and
- this.asExpr() = mc.getArgumentForName("destinationFileName")
- )
- }
- }
-
- /** A path argument to a `File.Open`, `File.OpenWrite`, or `File.Create` method call. */
- class FileOpenArgSink extends Sink {
- FileOpenArgSink() {
- exists(MethodCall mc |
- mc.getTarget().hasQualifiedName("System.IO.File", "Open") or
- mc.getTarget().hasQualifiedName("System.IO.File", "OpenWrite") or
- mc.getTarget().hasQualifiedName("System.IO.File", "Create")
- |
- this.asExpr() = mc.getArgumentForName("path")
- )
- }
- }
-
- /** A path argument to a call to the `FileStream` constructor. */
- class FileStreamArgSink extends Sink {
- FileStreamArgSink() {
- exists(ObjectCreation oc |
- oc.getTarget().getDeclaringType().hasQualifiedName("System.IO.FileStream")
- |
- this.asExpr() = oc.getArgumentForName("path")
- )
- }
- }
-
- /**
- * A path argument to a call to the `FileStream` constructor.
- *
- * This constructor can accept a tainted file name and subsequently be used to open a file stream.
- */
- class FileInfoArgSink extends Sink {
- FileInfoArgSink() {
- exists(ObjectCreation oc |
- oc.getTarget().getDeclaringType().hasQualifiedName("System.IO.FileInfo")
- |
- this.asExpr() = oc.getArgumentForName("fileName")
- )
- }
- }
-
- /**
- * A call to `GetFileName`.
- *
- * This is considered a sanitizer because it extracts just the file name, not the full path.
- */
- class GetFileNameSanitizer extends Sanitizer {
- GetFileNameSanitizer() {
- exists(MethodCall mc | mc.getTarget().hasQualifiedName("System.IO.Path", "GetFileName") |
- this.asExpr() = mc
- )
- }
- }
-
- /**
- * A call to `Substring`.
- *
- * This is considered a sanitizer because `Substring` may be used to extract a single component
- * of a path to avoid ZipSlip.
- */
- class SubstringSanitizer extends Sanitizer {
- SubstringSanitizer() {
- exists(MethodCall mc | mc.getTarget().hasQualifiedName("System.String", "Substring") |
- this.asExpr() = mc
- )
- }
- }
-
- /**
- * A call to `String.StartsWith()` that indicates that the tainted path value is being
- * validated to ensure that it occurs within a permitted output path.
- */
- class StringCheckGuard extends SanitizerGuard, MethodCall {
- private Expr q;
-
- StringCheckGuard() {
- this.getTarget().hasQualifiedName("System.String", "StartsWith") and
- this.getQualifier() = q and
- // A StartsWith check against Path.Combine is not sufficient, because the ".." elements have
- // not yet been resolved.
- not exists(MethodCall combineCall |
- combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and
- DataFlow::localExprFlow(combineCall, q)
- )
- }
-
- override predicate checks(Expr e, AbstractValue v) {
- e = q and
- v.(AbstractValues::BooleanValue).getValue() = true
- }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlipQuery.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlipQuery.qll
new file mode 100644
index 00000000000..fa809a374d5
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlipQuery.qll
@@ -0,0 +1,151 @@
+/**
+ * Provides a taint tracking configuration for reasoning about unsafe zip extraction.
+ */
+
+import csharp
+private import semmle.code.csharp.controlflow.Guards
+
+/**
+ * A data flow source for unsafe zip extraction.
+ */
+abstract class Source extends DataFlow::Node { }
+
+/**
+ * A data flow sink for unsafe zip extraction.
+ */
+abstract class Sink extends DataFlow::ExprNode { }
+
+/**
+ * A sanitizer for unsafe zip extraction.
+ */
+abstract class Sanitizer extends DataFlow::ExprNode { }
+
+/**
+ * A guard for unsafe zip extraction.
+ */
+abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
+
+/** A taint tracking configuration for Zip Slip */
+class TaintTrackingConfiguration extends TaintTracking::Configuration {
+ TaintTrackingConfiguration() { this = "ZipSlipTaintTracking" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+
+ override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
+ guard instanceof SanitizerGuard
+ }
+}
+
+/** An access to the `FullName` property of a `ZipArchiveEntry`. */
+class ArchiveFullNameSource extends Source {
+ ArchiveFullNameSource() {
+ exists(PropertyAccess pa | this.asExpr() = pa |
+ pa.getTarget().getDeclaringType().hasQualifiedName("System.IO.Compression.ZipArchiveEntry") and
+ pa.getTarget().getName() = "FullName"
+ )
+ }
+}
+
+/** An argument to the `ExtractToFile` extension method. */
+class ExtractToFileArgSink extends Sink {
+ ExtractToFileArgSink() {
+ exists(MethodCall mc |
+ mc.getTarget().hasQualifiedName("System.IO.Compression.ZipFileExtensions", "ExtractToFile") and
+ this.asExpr() = mc.getArgumentForName("destinationFileName")
+ )
+ }
+}
+
+/** A path argument to a `File.Open`, `File.OpenWrite`, or `File.Create` method call. */
+class FileOpenArgSink extends Sink {
+ FileOpenArgSink() {
+ exists(MethodCall mc |
+ mc.getTarget().hasQualifiedName("System.IO.File", "Open") or
+ mc.getTarget().hasQualifiedName("System.IO.File", "OpenWrite") or
+ mc.getTarget().hasQualifiedName("System.IO.File", "Create")
+ |
+ this.asExpr() = mc.getArgumentForName("path")
+ )
+ }
+}
+
+/** A path argument to a call to the `FileStream` constructor. */
+class FileStreamArgSink extends Sink {
+ FileStreamArgSink() {
+ exists(ObjectCreation oc |
+ oc.getTarget().getDeclaringType().hasQualifiedName("System.IO.FileStream")
+ |
+ this.asExpr() = oc.getArgumentForName("path")
+ )
+ }
+}
+
+/**
+ * A path argument to a call to the `FileStream` constructor.
+ *
+ * This constructor can accept a tainted file name and subsequently be used to open a file stream.
+ */
+class FileInfoArgSink extends Sink {
+ FileInfoArgSink() {
+ exists(ObjectCreation oc |
+ oc.getTarget().getDeclaringType().hasQualifiedName("System.IO.FileInfo")
+ |
+ this.asExpr() = oc.getArgumentForName("fileName")
+ )
+ }
+}
+
+/**
+ * A call to `GetFileName`.
+ *
+ * This is considered a sanitizer because it extracts just the file name, not the full path.
+ */
+class GetFileNameSanitizer extends Sanitizer {
+ GetFileNameSanitizer() {
+ exists(MethodCall mc | mc.getTarget().hasQualifiedName("System.IO.Path", "GetFileName") |
+ this.asExpr() = mc
+ )
+ }
+}
+
+/**
+ * A call to `Substring`.
+ *
+ * This is considered a sanitizer because `Substring` may be used to extract a single component
+ * of a path to avoid ZipSlip.
+ */
+class SubstringSanitizer extends Sanitizer {
+ SubstringSanitizer() {
+ exists(MethodCall mc | mc.getTarget().hasQualifiedName("System.String", "Substring") |
+ this.asExpr() = mc
+ )
+ }
+}
+
+/**
+ * A call to `String.StartsWith()` that indicates that the tainted path value is being
+ * validated to ensure that it occurs within a permitted output path.
+ */
+class StringCheckGuard extends SanitizerGuard, MethodCall {
+ private Expr q;
+
+ StringCheckGuard() {
+ this.getTarget().hasQualifiedName("System.String", "StartsWith") and
+ this.getQualifier() = q and
+ // A StartsWith check against Path.Combine is not sufficient, because the ".." elements have
+ // not yet been resolved.
+ not exists(MethodCall combineCall |
+ combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and
+ DataFlow::localExprFlow(combineCall, q)
+ )
+ }
+
+ override predicate checks(Expr e, AbstractValue v) {
+ e = q and
+ v.(AbstractValues::BooleanValue).getValue() = true
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll
index 97b81b6561e..aaf9b1a9919 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll
@@ -13,6 +13,7 @@ private import semmle.code.csharp.frameworks.system.web.UI
private import semmle.code.csharp.frameworks.system.web.ui.WebControls
private import semmle.code.csharp.frameworks.system.windows.Forms
private import semmle.code.csharp.security.dataflow.flowsources.Remote
+private import semmle.code.csharp.dataflow.ExternalFlow
private import semmle.code.asp.AspNet
/**
@@ -21,21 +22,23 @@ private import semmle.code.asp.AspNet
*/
abstract class HtmlSink extends DataFlow::ExprNode, RemoteFlowSink { }
+private class ExternalHtmlSink extends HtmlSink {
+ ExternalHtmlSink() { sinkNode(this, "html") }
+}
+
/**
* An expression that is used as an argument to an HTML sink method on
* `HttpResponse`.
*/
-class HttpResponseSink extends HtmlSink {
- HttpResponseSink() {
- exists(Method m, SystemWebHttpResponseClass responseClass |
- m = responseClass.getAWriteMethod() or
- m = responseClass.getAWriteFileMethod() or
- m = responseClass.getATransmitFileMethod() or
- m = responseClass.getABinaryWriteMethod()
- |
- // Calls to these methods, or overrides of them
- this.getExpr() = m.getAnOverrider*().getParameter(0).getAnAssignedArgument()
- )
+private class HttpResponseSinkModelCsv extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "System.Web;HttpResponse;false;Write;;;Argument[0];html",
+ "System.Web;HttpResponse;false;WriteFile;;;Argument[0];html",
+ "System.Web;HttpResponse;false;TransmitFile;;;Argument[0];html",
+ "System.Web;HttpResponse;false;BinaryWrite;;;Argument[0];html"
+ ]
}
}
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll
index 10885d52a16..b194ad57d57 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll
@@ -6,7 +6,7 @@ import csharp
private import Email::Email
private import ExternalLocationSink
private import Html
-private import semmle.code.csharp.security.dataflow.XSS
+private import semmle.code.csharp.security.dataflow.XSSSinks as XSSSinks
private import semmle.code.csharp.frameworks.system.web.UI
/** A data flow sink of remote user output. */
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Local.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Local.qll
index 4c7f70921d9..fc63c143a5f 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Local.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsources/Local.qll
@@ -4,6 +4,7 @@
import csharp
private import semmle.code.csharp.frameworks.system.windows.Forms
+private import semmle.code.csharp.dataflow.ExternalFlow
/** A data flow source of local data. */
abstract class LocalFlowSource extends DataFlow::Node {
@@ -11,6 +12,12 @@ abstract class LocalFlowSource extends DataFlow::Node {
abstract string getSourceType();
}
+private class ExternalLocalFlowSource extends LocalFlowSource {
+ ExternalLocalFlowSource() { sourceNode(this, "local") }
+
+ override string getSourceType() { result = "external" }
+}
+
/** A data flow source of local user input. */
abstract class LocalUserInputSource extends LocalFlowSource { }
@@ -22,13 +29,13 @@ class TextFieldSource extends LocalUserInputSource {
}
/** A call to any `System.Console.Read*` method. */
-class SystemConsoleReadSource extends LocalUserInputSource {
- SystemConsoleReadSource() {
- this.asExpr() =
- any(MethodCall call |
- call.getTarget().hasQualifiedName("System.Console", ["ReadLine", "Read", "ReadKey"])
- )
+private class SystemConsoleReadSourceModelCsv extends SourceModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "System;Console;false;ReadLine;;;ReturnValue;local",
+ "System;Console;false;Read;;;ReturnValue;local",
+ "System;Console;false;ReadKey;;;ReturnValue;local"
+ ]
}
-
- override string getSourceType() { result = "System.Console input" }
}
diff --git a/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll b/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll
deleted file mode 100644
index 34e6c142b19..00000000000
--- a/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * Provides classes and predicates for detecting insecure processing of XML documents.
- */
-
-import csharp
-
-module InsecureXML {
- import semmle.code.csharp.commons.TargetFramework
-
- /**
- * Holds if the type `t` is in an assembly that has been compiled against a .NET framework version
- * before the given version.
- */
- bindingset[version]
- private predicate isNetFrameworkBefore(Type t, string version) {
- // For assemblies compiled against framework versions before 4 the TargetFrameworkAttribute
- // will not be present. In this case, we can revert back to the assembly version, which may not
- // contain full minor version information.
- exists(string assemblyVersion |
- assemblyVersion =
- t.getALocation().(Assembly).getVersion().regexpCapture("([0-9]+\\.[0-9]+).*", 1)
- |
- assemblyVersion.toFloat() < version.toFloat() and
- // This method is only accurate when we're looking at versions before 4.0.
- assemblyVersion.toFloat() < 4.0
- )
- or
- // For 4.0 and above the TargetFrameworkAttribute should be present to provide detailed version
- // information.
- exists(TargetFrameworkAttribute tfa |
- tfa.hasElement(t) and
- tfa.isNetFramework() and
- tfa.getFrameworkVersion().isEarlierThan(version)
- )
- }
-
- /**
- * A call which may load an XML document insecurely.
- */
- abstract class InsecureXmlProcessing extends Call {
- /**
- * Holds if this call is in fact unsafe, with the reason given.
- */
- abstract predicate isUnsafe(string reason);
- }
-
- /**
- * Holds if this expression is a secure `XmlResolver`.
- */
- private predicate isSafeXmlResolver(Expr e) {
- e instanceof NullLiteral or
- e.getType().(RefType).hasQualifiedName("System.Xml.XmlSecureResolver")
- }
-
- /**
- * Holds if this expression is a safe DTD processing setting.
- */
- private predicate isSafeDtdSetting(Expr e) {
- // new DtdProcessing setting
- exists(string name | e.(FieldAccess).getTarget().(EnumConstant).getName() = name |
- name = "Prohibit" or name = "Ignore"
- )
- or
- // old ProhibitDtd setting
- e.(BoolLiteral).getValue() = "true"
- }
-
- /**
- * A simplistic points-to alternative: given an object creation and a property name, get the values that property can be assigned.
- *
- * Assumptions:
- * - we don't reassign the variable that the creation is stored in
- * - we always access the creation through the same variable it is initially assigned to
- *
- * This should cover most typical patterns...
- */
- private Expr getAValueForProp(ObjectCreation create, string prop) {
- // values set in object init
- exists(MemberInitializer init |
- init = create.getInitializer().(ObjectInitializer).getAMemberInitializer() and
- init.getLValue().(PropertyAccess).getTarget().hasName(prop) and
- result = init.getRValue()
- )
- or
- // values set on var that create is assigned to
- exists(Assignment propAssign |
- DataFlow::localExprFlow(create, propAssign.getLValue().(PropertyAccess).getQualifier()) and
- propAssign.getLValue().(PropertyAccess).getTarget().hasName(prop) and
- result = propAssign.getRValue()
- )
- }
-
- module XmlSettings {
- /**
- * Holds if the given object creation constructs `XmlReaderSettings` with an insecure resolver.
- */
- predicate insecureResolverSettings(ObjectCreation creation, Expr evidence, string reason) {
- creation.getObjectType().getQualifiedName() = "System.Xml.XmlReaderSettings" and
- (
- // one unsafe assignment to XmlResolver
- exists(Expr xmlResolverVal | xmlResolverVal = getAValueForProp(creation, "XmlResolver") |
- not isSafeXmlResolver(xmlResolverVal) and evidence = xmlResolverVal
- ) and
- reason = "insecure resolver set in settings"
- or
- // no assignments, and default is insecure before version 4.5
- isNetFrameworkBefore(creation.getObjectType(), "4.5") and
- not exists(getAValueForProp(creation, "XmlResolver")) and
- reason = "default settings resolver is insecure in versions before 4.5" and
- evidence = creation
- )
- }
-
- /**
- * Holds if the given object creation constructs `XmlReaderSettings` with DTD processing enabled.
- */
- predicate dtdEnabledSettings(ObjectCreation creation, Expr evidence, string reason) {
- creation.getObjectType().getQualifiedName() = "System.Xml.XmlReaderSettings" and
- (
- exists(Expr dtdVal | dtdVal = getAValueForProp(creation, "DtdProcessing") |
- not isSafeDtdSetting(dtdVal) and evidence = dtdVal
- ) and
- reason = "DTD processing enabled in settings"
- or
- // default is secure in versions >= 4
- isNetFrameworkBefore(creation.getObjectType(), "4.0") and
- (
- exists(Expr dtdVal |
- // different DTD setting before version 4
- dtdVal = getAValueForProp(creation, "ProhibitDtd")
- |
- not isSafeDtdSetting(dtdVal) and evidence = dtdVal
- ) and
- reason = "DTD procesing enabled in settings"
- or
- not exists(getAValueForProp(creation, "ProhibitDtd")) and
- reason = "DTD processing is enabled by default in versions before 4.0" and
- evidence = creation
- )
- )
- }
- }
-
- module XmlReader {
- private import semmle.code.csharp.dataflow.DataFlow2
-
- class InsecureXmlReaderCreate extends InsecureXmlProcessing, MethodCall {
- InsecureXmlReaderCreate() { this.getTarget().hasQualifiedName("System.Xml.XmlReader.Create") }
-
- /**
- * Gets the `XmlReaderSettings` argument to to this call, if any.
- */
- Expr getSettings() {
- result = this.getAnArgument() and
- result.getType().(RefType).getABaseType*().hasQualifiedName("System.Xml.XmlReaderSettings")
- }
-
- override predicate isUnsafe(string reason) {
- exists(string dtdReason, string resolverReason |
- dtdEnabled(dtdReason, _) and
- insecureResolver(resolverReason, _) and
- reason = dtdReason + ", " + resolverReason
- )
- }
-
- private predicate dtdEnabled(string reason, Expr evidence) {
- reason = "DTD processing is enabled by default in versions < 4.0" and
- evidence = this and
- not exists(this.getSettings()) and
- isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
- or
- // bad settings flow here
- exists(SettingsDataFlowConfig flow, ObjectCreation settings |
- flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
- XmlSettings::dtdEnabledSettings(settings, evidence, reason)
- )
- }
-
- private predicate insecureResolver(string reason, Expr evidence) {
- // bad settings flow here
- exists(SettingsDataFlowConfig flow, ObjectCreation settings |
- flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
- XmlSettings::insecureResolverSettings(settings, evidence, reason)
- )
- // default is secure
- }
- }
-
- private class SettingsDataFlowConfig extends DataFlow2::Configuration {
- SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
-
- override predicate isSource(DataFlow::Node source) {
- // flow from places where we construct an XmlReaderSettings
- source
- .asExpr()
- .(ObjectCreation)
- .getType()
- .(RefType)
- .getABaseType*()
- .hasQualifiedName("System.Xml.XmlReaderSettings")
- }
-
- override predicate isSink(DataFlow::Node sink) {
- sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
- }
- }
- }
-
- module XmlTextReader {
- class InsecureXmlTextReader extends InsecureXmlProcessing, ObjectCreation {
- InsecureXmlTextReader() {
- this.getObjectType().(ValueOrRefType).hasQualifiedName("System.Xml.XmlTextReader")
- }
-
- override predicate isUnsafe(string reason) {
- not exists(Expr xmlResolverVal |
- isSafeXmlResolver(xmlResolverVal) and
- xmlResolverVal = getAValueForProp(this, "XmlResolver")
- ) and
- not exists(Expr dtdVal |
- isSafeDtdSetting(dtdVal) and
- dtdVal = getAValueForProp(this, "DtdProcessing")
- ) and
- // This was made safe by default in 4.5.2, despite what the documentation says
- isNetFrameworkBefore(this.getObjectType(), "4.5.2") and
- reason = "DTD processing is enabled by default, and resolver is insecure by default"
- or
- exists(Expr xmlResolverVal |
- not isSafeXmlResolver(xmlResolverVal) and
- xmlResolverVal = getAValueForProp(this, "XmlResolver")
- ) and
- exists(Expr dtdVal |
- not isSafeDtdSetting(dtdVal) and
- dtdVal = getAValueForProp(this, "DtdProcessing")
- ) and
- reason = "DTD processing is enabled with an insecure resolver"
- }
- }
- }
-
- module XmlDocument {
- /**
- * A call to `Load` or `LoadXml` on `XmlDocument`s that doesn't appear to have a safe `XmlResolver` set.
- */
- class InsecureXmlDocument extends InsecureXmlProcessing, MethodCall {
- InsecureXmlDocument() {
- this.getTarget().hasQualifiedName("System.Xml.XmlDocument.Load") or
- this.getTarget().hasQualifiedName("System.Xml.XmlDocument.LoadXml")
- }
-
- override predicate isUnsafe(string reason) {
- exists(ObjectCreation creation | DataFlow::localExprFlow(creation, this.getQualifier()) |
- not exists(Expr xmlResolverVal |
- isSafeXmlResolver(xmlResolverVal) and
- xmlResolverVal = getAValueForProp(creation, "XmlResolver")
- )
- ) and
- isNetFrameworkBefore(this.getQualifier().getType(), "4.6") and
- reason = "resolver is insecure by default in versions before 4.6"
- }
- }
- }
-}
diff --git a/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXMLQuery.qll b/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXMLQuery.qll
new file mode 100644
index 00000000000..2483452113a
--- /dev/null
+++ b/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXMLQuery.qll
@@ -0,0 +1,264 @@
+/**
+ * Provides classes and predicates for detecting insecure processing of XML documents.
+ */
+
+import csharp
+private import semmle.code.csharp.commons.TargetFramework
+
+/**
+ * Holds if the type `t` is in an assembly that has been compiled against a .NET framework version
+ * before the given version.
+ */
+bindingset[version]
+private predicate isNetFrameworkBefore(Type t, string version) {
+ // For assemblies compiled against framework versions before 4 the TargetFrameworkAttribute
+ // will not be present. In this case, we can revert back to the assembly version, which may not
+ // contain full minor version information.
+ exists(string assemblyVersion |
+ assemblyVersion =
+ t.getALocation().(Assembly).getVersion().regexpCapture("([0-9]+\\.[0-9]+).*", 1)
+ |
+ assemblyVersion.toFloat() < version.toFloat() and
+ // This method is only accurate when we're looking at versions before 4.0.
+ assemblyVersion.toFloat() < 4.0
+ )
+ or
+ // For 4.0 and above the TargetFrameworkAttribute should be present to provide detailed version
+ // information.
+ exists(TargetFrameworkAttribute tfa |
+ tfa.hasElement(t) and
+ tfa.isNetFramework() and
+ tfa.getFrameworkVersion().isEarlierThan(version)
+ )
+}
+
+/**
+ * A call which may load an XML document insecurely.
+ */
+abstract class InsecureXmlProcessing extends Call {
+ /**
+ * Holds if this call is in fact unsafe, with the reason given.
+ */
+ abstract predicate isUnsafe(string reason);
+}
+
+/**
+ * Holds if this expression is a secure `XmlResolver`.
+ */
+private predicate isSafeXmlResolver(Expr e) {
+ e instanceof NullLiteral or
+ e.getType().(RefType).hasQualifiedName("System.Xml.XmlSecureResolver")
+}
+
+/**
+ * Holds if this expression is a safe DTD processing setting.
+ */
+private predicate isSafeDtdSetting(Expr e) {
+ // new DtdProcessing setting
+ exists(string name | e.(FieldAccess).getTarget().(EnumConstant).getName() = name |
+ name = "Prohibit" or name = "Ignore"
+ )
+ or
+ // old ProhibitDtd setting
+ e.(BoolLiteral).getValue() = "true"
+}
+
+/**
+ * A simplistic points-to alternative: given an object creation and a property name, get the values that property can be assigned.
+ *
+ * Assumptions:
+ * - we don't reassign the variable that the creation is stored in
+ * - we always access the creation through the same variable it is initially assigned to
+ *
+ * This should cover most typical patterns...
+ */
+private Expr getAValueForProp(ObjectCreation create, string prop) {
+ // values set in object init
+ exists(MemberInitializer init |
+ init = create.getInitializer().(ObjectInitializer).getAMemberInitializer() and
+ init.getLValue().(PropertyAccess).getTarget().hasName(prop) and
+ result = init.getRValue()
+ )
+ or
+ // values set on var that create is assigned to
+ exists(Assignment propAssign |
+ DataFlow::localExprFlow(create, propAssign.getLValue().(PropertyAccess).getQualifier()) and
+ propAssign.getLValue().(PropertyAccess).getTarget().hasName(prop) and
+ result = propAssign.getRValue()
+ )
+}
+
+/** Provides predicates related to `System.Xml.XmlReaderSettings`. */
+module XmlSettings {
+ /**
+ * Holds if the given object creation constructs `XmlReaderSettings` with an insecure resolver.
+ */
+ predicate insecureResolverSettings(ObjectCreation creation, Expr evidence, string reason) {
+ creation.getObjectType().getQualifiedName() = "System.Xml.XmlReaderSettings" and
+ (
+ // one unsafe assignment to XmlResolver
+ exists(Expr xmlResolverVal | xmlResolverVal = getAValueForProp(creation, "XmlResolver") |
+ not isSafeXmlResolver(xmlResolverVal) and evidence = xmlResolverVal
+ ) and
+ reason = "insecure resolver set in settings"
+ or
+ // no assignments, and default is insecure before version 4.5
+ isNetFrameworkBefore(creation.getObjectType(), "4.5") and
+ not exists(getAValueForProp(creation, "XmlResolver")) and
+ reason = "default settings resolver is insecure in versions before 4.5" and
+ evidence = creation
+ )
+ }
+
+ /**
+ * Holds if the given object creation constructs `XmlReaderSettings` with DTD processing enabled.
+ */
+ predicate dtdEnabledSettings(ObjectCreation creation, Expr evidence, string reason) {
+ creation.getObjectType().getQualifiedName() = "System.Xml.XmlReaderSettings" and
+ (
+ exists(Expr dtdVal | dtdVal = getAValueForProp(creation, "DtdProcessing") |
+ not isSafeDtdSetting(dtdVal) and evidence = dtdVal
+ ) and
+ reason = "DTD processing enabled in settings"
+ or
+ // default is secure in versions >= 4
+ isNetFrameworkBefore(creation.getObjectType(), "4.0") and
+ (
+ exists(Expr dtdVal |
+ // different DTD setting before version 4
+ dtdVal = getAValueForProp(creation, "ProhibitDtd")
+ |
+ not isSafeDtdSetting(dtdVal) and evidence = dtdVal
+ ) and
+ reason = "DTD procesing enabled in settings"
+ or
+ not exists(getAValueForProp(creation, "ProhibitDtd")) and
+ reason = "DTD processing is enabled by default in versions before 4.0" and
+ evidence = creation
+ )
+ )
+ }
+}
+
+/** Provides predicates related to `System.Xml.XmlReader`. */
+module XmlReader {
+ private import semmle.code.csharp.dataflow.DataFlow2
+
+ private class InsecureXmlReaderCreate extends InsecureXmlProcessing, MethodCall {
+ InsecureXmlReaderCreate() { this.getTarget().hasQualifiedName("System.Xml.XmlReader.Create") }
+
+ /**
+ * Gets the `XmlReaderSettings` argument to to this call, if any.
+ */
+ Expr getSettings() {
+ result = this.getAnArgument() and
+ result.getType().(RefType).getABaseType*().hasQualifiedName("System.Xml.XmlReaderSettings")
+ }
+
+ override predicate isUnsafe(string reason) {
+ exists(string dtdReason, string resolverReason |
+ dtdEnabled(dtdReason, _) and
+ insecureResolver(resolverReason, _) and
+ reason = dtdReason + ", " + resolverReason
+ )
+ }
+
+ private predicate dtdEnabled(string reason, Expr evidence) {
+ reason = "DTD processing is enabled by default in versions < 4.0" and
+ evidence = this and
+ not exists(this.getSettings()) and
+ isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
+ or
+ // bad settings flow here
+ exists(SettingsDataFlowConfig flow, ObjectCreation settings |
+ flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
+ XmlSettings::dtdEnabledSettings(settings, evidence, reason)
+ )
+ }
+
+ private predicate insecureResolver(string reason, Expr evidence) {
+ // bad settings flow here
+ exists(SettingsDataFlowConfig flow, ObjectCreation settings |
+ flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
+ XmlSettings::insecureResolverSettings(settings, evidence, reason)
+ )
+ // default is secure
+ }
+ }
+
+ private class SettingsDataFlowConfig extends DataFlow2::Configuration {
+ SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ // flow from places where we construct an XmlReaderSettings
+ source
+ .asExpr()
+ .(ObjectCreation)
+ .getType()
+ .(RefType)
+ .getABaseType*()
+ .hasQualifiedName("System.Xml.XmlReaderSettings")
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
+ }
+ }
+}
+
+/** Provides predicates related to `System.Xml.XmlTextReader`. */
+module XmlTextReader {
+ private class InsecureXmlTextReader extends InsecureXmlProcessing, ObjectCreation {
+ InsecureXmlTextReader() {
+ this.getObjectType().(ValueOrRefType).hasQualifiedName("System.Xml.XmlTextReader")
+ }
+
+ override predicate isUnsafe(string reason) {
+ not exists(Expr xmlResolverVal |
+ isSafeXmlResolver(xmlResolverVal) and
+ xmlResolverVal = getAValueForProp(this, "XmlResolver")
+ ) and
+ not exists(Expr dtdVal |
+ isSafeDtdSetting(dtdVal) and
+ dtdVal = getAValueForProp(this, "DtdProcessing")
+ ) and
+ // This was made safe by default in 4.5.2, despite what the documentation says
+ isNetFrameworkBefore(this.getObjectType(), "4.5.2") and
+ reason = "DTD processing is enabled by default, and resolver is insecure by default"
+ or
+ exists(Expr xmlResolverVal |
+ not isSafeXmlResolver(xmlResolverVal) and
+ xmlResolverVal = getAValueForProp(this, "XmlResolver")
+ ) and
+ exists(Expr dtdVal |
+ not isSafeDtdSetting(dtdVal) and
+ dtdVal = getAValueForProp(this, "DtdProcessing")
+ ) and
+ reason = "DTD processing is enabled with an insecure resolver"
+ }
+ }
+}
+
+/** Provides predicates related to `System.Xml.XmlDocument`. */
+module XmlDocument {
+ /**
+ * A call to `Load` or `LoadXml` on `XmlDocument`s that doesn't appear to have a safe `XmlResolver` set.
+ */
+ class InsecureXmlDocument extends InsecureXmlProcessing, MethodCall {
+ InsecureXmlDocument() {
+ this.getTarget().hasQualifiedName("System.Xml.XmlDocument.Load") or
+ this.getTarget().hasQualifiedName("System.Xml.XmlDocument.LoadXml")
+ }
+
+ override predicate isUnsafe(string reason) {
+ exists(ObjectCreation creation | DataFlow::localExprFlow(creation, this.getQualifier()) |
+ not exists(Expr xmlResolverVal |
+ isSafeXmlResolver(xmlResolverVal) and
+ xmlResolverVal = getAValueForProp(creation, "XmlResolver")
+ )
+ ) and
+ isNetFrameworkBefore(this.getQualifier().getType(), "4.6") and
+ reason = "resolver is insecure by default in versions before 4.6"
+ }
+ }
+}
diff --git a/csharp/ql/src/semmle/code/dotnet/Element.qll b/csharp/ql/src/semmle/code/dotnet/Element.qll
index c38b09ce270..1f23c43215d 100644
--- a/csharp/ql/src/semmle/code/dotnet/Element.qll
+++ b/csharp/ql/src/semmle/code/dotnet/Element.qll
@@ -74,6 +74,7 @@ class NamedElement extends Element, @dotnet_named_element {
* }
* ```
*/
+ cached
final string getQualifiedName() {
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
@@ -87,6 +88,7 @@ class NamedElement extends Element, @dotnet_named_element {
final predicate hasQualifiedName(string qualifiedName) { qualifiedName = this.getQualifiedName() }
/** Holds if this element has the qualified name `qualifier`.`name`. */
+ cached
predicate hasQualifiedName(string qualifier, string name) {
qualifier = "" and name = this.getName()
}
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected
index 8d01c5e62b4..923d680e356 100644
--- a/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected
+++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningDatasetRelatedType.expected
@@ -1,2 +1,2 @@
-| test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
-| test0.cs:59:18:59:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
+| test0.cs:11:18:11:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
+| test0.cs:57:18:57:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected
index 5b90d0c0a64..03518e4342b 100644
--- a/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected
+++ b/csharp/ql/test/experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected
@@ -1,2 +1,2 @@
-| test0.cs:15:24:15:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:15:24:15:32 | MyDataSet | MyDataSet |
-| test0.cs:61:25:61:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:59:18:59:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:61:25:61:33 | MyDataSet | MyDataSet |
+| test0.cs:13:24:13:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:11:18:11:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:13:24:13:32 | MyDataSet | MyDataSet |
+| test0.cs:59:25:59:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:57:18:57:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:59:25:59:33 | MyDataSet | MyDataSet |
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected
index 0c9ce7297e9..421cae01530 100644
--- a/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected
+++ b/csharp/ql/test/experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.expected
@@ -1,2 +1,2 @@
-| test0.cs:95:49:95:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:95:49:95:63 | typeof(...) | typeof(...) |
-| test0.cs:96:49:96:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:96:49:96:77 | typeof(...) | typeof(...) |
+| test0.cs:93:49:93:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:93:49:93:63 | typeof(...) | typeof(...) |
+| test0.cs:94:49:94:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:94:49:94:77 | typeof(...) | typeof(...) |
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected
index 4f451559aaf..be451487ad4 100644
--- a/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected
+++ b/csharp/ql/test/experimental/Security Features/Serialization/XmlDeserializationWithDataSet.expected
@@ -1 +1 @@
-| test0.cs:88:17:88:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
+| test0.cs:86:17:86:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/options b/csharp/ql/test/experimental/Security Features/Serialization/options
new file mode 100644
index 00000000000..670ea383c41
--- /dev/null
+++ b/csharp/ql/test/experimental/Security Features/Serialization/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Data.Common.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll
diff --git a/csharp/ql/test/experimental/Security Features/Serialization/test0.cs b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs
index 2efcb4facf3..d2b2e772245 100644
--- a/csharp/ql/test/experimental/Security Features/Serialization/test0.cs
+++ b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll
-
using System;
using System.Data;
using System.IO;
@@ -98,4 +96,4 @@ namespace DataSetSerializationTest
Console.WriteLine("Hello World!");
}
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected
index da578042bc3..a82479c30bd 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected
@@ -1 +1 @@
-| test.cs:40:16:40:36 | 6605813339339102567 | The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@. | test.cs:26:9:26:11 | num | num | test.cs:40:10:40:36 | ... ^ ... | xor | test.cs:40:16:40:36 | 6605813339339102567 | 6605813339339102567 |
+| test.cs:39:16:39:36 | 6605813339339102567 | The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@. | test.cs:25:9:25:11 | num | num | test.cs:39:10:39:36 | ... ^ ... | xor | test.cs:39:16:39:36 | 6605813339339102567 | 6605813339339102567 |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected
index fa8afc54079..884483a4e79 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected
@@ -1 +1 @@
-| test.cs:43:7:43:15 | JobEngine | The enum $@ may be related to Solorigate. It matches 19 of the values used for commands in the enum. | test.cs:43:7:43:15 | JobEngine | JobEngine |
+| test.cs:42:7:42:15 | JobEngine | The enum $@ may be related to Solorigate. It matches 19 of the values used for commands in the enum. | test.cs:42:7:42:15 | JobEngine | JobEngine |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected
index 3603cf8a20a..1ed75ff8bc5 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected
@@ -1,248 +1,248 @@
-| test.cs:10:15:10:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:10:15:10:36 | 14695981039346656037 | 14695981039346656037 |
-| test.cs:15:11:15:25 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:15:11:15:25 | 1099511628211 | 1099511628211 |
-| test.cs:26:15:26:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:26:15:26:36 | 14695981039346656037 | 14695981039346656037 |
-| test.cs:32:12:32:26 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:32:12:32:26 | 1099511628211 | 1099511628211 |
-| test.cs:40:16:40:36 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:40:16:40:36 | 6605813339339102567 | 6605813339339102567 |
-| test.cs:173:5:173:24 | 10063651499895178962 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:5:173:24 | 10063651499895178962 | 10063651499895178962 |
-| test.cs:173:27:173:46 | 10235971842993272939 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:27:173:46 | 10235971842993272939 | 10235971842993272939 |
-| test.cs:173:49:173:68 | 10296494671777307979 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:49:173:68 | 10296494671777307979 | 10296494671777307979 |
-| test.cs:174:5:174:24 | 10336842116636872171 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:5:174:24 | 10336842116636872171 | 10336842116636872171 |
-| test.cs:174:27:174:46 | 10374841591685794123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:27:174:46 | 10374841591685794123 | 10374841591685794123 |
-| test.cs:174:49:174:68 | 10393903804869831898 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:49:174:68 | 10393903804869831898 | 10393903804869831898 |
-| test.cs:175:5:175:24 | 10463926208560207521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:5:175:24 | 10463926208560207521 | 10463926208560207521 |
-| test.cs:175:27:175:46 | 10484659978517092504 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:27:175:46 | 10484659978517092504 | 10484659978517092504 |
-| test.cs:175:49:175:68 | 10501212300031893463 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:49:175:68 | 10501212300031893463 | 10501212300031893463 |
-| test.cs:176:5:176:24 | 10545868833523019926 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:5:176:24 | 10545868833523019926 | 10545868833523019926 |
-| test.cs:176:27:176:46 | 10657751674541025650 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:27:176:46 | 10657751674541025650 | 10657751674541025650 |
-| test.cs:176:49:176:66 | 106672141413120087 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:49:176:66 | 106672141413120087 | 106672141413120087 |
-| test.cs:176:69:176:88 | 10734127004244879770 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:69:176:88 | 10734127004244879770 | 10734127004244879770 |
-| test.cs:177:5:177:24 | 10829648878147112121 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:5:177:24 | 10829648878147112121 | 10829648878147112121 |
-| test.cs:177:27:177:39 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:27:177:39 | 1099511628211 | 1099511628211 |
-| test.cs:177:42:177:61 | 11073283311104541690 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:42:177:61 | 11073283311104541690 | 11073283311104541690 |
-| test.cs:177:64:177:82 | 1109067043404435916 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:64:177:82 | 1109067043404435916 | 1109067043404435916 |
-| test.cs:178:5:178:24 | 11109294216876344399 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:5:178:24 | 11109294216876344399 | 11109294216876344399 |
-| test.cs:178:27:178:46 | 11266044540366291518 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:27:178:46 | 11266044540366291518 | 11266044540366291518 |
-| test.cs:178:49:178:68 | 11385275378891906608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:49:178:68 | 11385275378891906608 | 11385275378891906608 |
-| test.cs:179:5:179:24 | 11771945869106552231 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:5:179:24 | 11771945869106552231 | 11771945869106552231 |
-| test.cs:179:27:179:46 | 11801746708619571308 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:27:179:46 | 11801746708619571308 | 11801746708619571308 |
-| test.cs:179:49:179:68 | 11818825521849580123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:49:179:68 | 11818825521849580123 | 11818825521849580123 |
-| test.cs:180:5:180:24 | 11913842725949116895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:5:180:24 | 11913842725949116895 | 11913842725949116895 |
-| test.cs:180:27:180:46 | 12027963942392743532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:27:180:46 | 12027963942392743532 | 12027963942392743532 |
-| test.cs:180:49:180:68 | 12094027092655598256 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:49:180:68 | 12094027092655598256 | 12094027092655598256 |
-| test.cs:181:5:181:24 | 12343334044036541897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:5:181:24 | 12343334044036541897 | 12343334044036541897 |
-| test.cs:181:27:181:46 | 12445177985737237804 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:27:181:46 | 12445177985737237804 | 12445177985737237804 |
-| test.cs:181:49:181:68 | 12445232961318634374 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:49:181:68 | 12445232961318634374 | 12445232961318634374 |
-| test.cs:182:5:182:24 | 12574535824074203265 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:5:182:24 | 12574535824074203265 | 12574535824074203265 |
-| test.cs:182:27:182:46 | 12679195163651834776 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:27:182:46 | 12679195163651834776 | 12679195163651834776 |
-| test.cs:182:49:182:68 | 12709986806548166638 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:49:182:68 | 12709986806548166638 | 12709986806548166638 |
-| test.cs:183:5:183:24 | 12718416789200275332 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:5:183:24 | 12718416789200275332 | 12718416789200275332 |
-| test.cs:183:27:183:46 | 12785322942775634499 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:27:183:46 | 12785322942775634499 | 12785322942775634499 |
-| test.cs:183:49:183:68 | 12790084614253405985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:49:183:68 | 12790084614253405985 | 12790084614253405985 |
-| test.cs:184:5:184:24 | 12969190449276002545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:5:184:24 | 12969190449276002545 | 12969190449276002545 |
-| test.cs:184:27:184:46 | 13014156621614176974 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:27:184:46 | 13014156621614176974 | 13014156621614176974 |
-| test.cs:184:49:184:68 | 13029357933491444455 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:49:184:68 | 13029357933491444455 | 13029357933491444455 |
-| test.cs:185:5:185:24 | 13135068273077306806 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:5:185:24 | 13135068273077306806 | 13135068273077306806 |
-| test.cs:185:27:185:46 | 13260224381505715848 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:27:185:46 | 13260224381505715848 | 13260224381505715848 |
-| test.cs:185:49:185:68 | 13316211011159594063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:49:185:68 | 13316211011159594063 | 13316211011159594063 |
-| test.cs:186:5:186:24 | 13464308873961738403 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:5:186:24 | 13464308873961738403 | 13464308873961738403 |
-| test.cs:186:27:186:46 | 13544031715334011032 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:27:186:46 | 13544031715334011032 | 13544031715334011032 |
-| test.cs:186:49:186:68 | 13581776705111912829 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:49:186:68 | 13581776705111912829 | 13581776705111912829 |
-| test.cs:187:5:187:24 | 13599785766252827703 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:5:187:24 | 13599785766252827703 | 13599785766252827703 |
-| test.cs:187:27:187:46 | 13611051401579634621 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:27:187:46 | 13611051401579634621 | 13611051401579634621 |
-| test.cs:187:49:187:68 | 13611814135072561278 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:49:187:68 | 13611814135072561278 | 13611814135072561278 |
-| test.cs:188:5:188:24 | 13655261125244647696 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:5:188:24 | 13655261125244647696 | 13655261125244647696 |
-| test.cs:188:27:188:45 | 1367627386496056834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:27:188:45 | 1367627386496056834 | 1367627386496056834 |
-| test.cs:188:48:188:66 | 1368907909245890092 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:48:188:66 | 1368907909245890092 | 1368907909245890092 |
-| test.cs:188:69:188:88 | 13693525876560827283 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:69:188:88 | 13693525876560827283 | 13693525876560827283 |
-| test.cs:189:5:189:24 | 13783346438774742614 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:5:189:24 | 13783346438774742614 | 13783346438774742614 |
-| test.cs:189:27:189:46 | 13799353263187722717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:27:189:46 | 13799353263187722717 | 13799353263187722717 |
-| test.cs:189:49:189:68 | 13825071784440082496 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:49:189:68 | 13825071784440082496 | 13825071784440082496 |
-| test.cs:190:5:190:24 | 13852439084267373191 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:5:190:24 | 13852439084267373191 | 13852439084267373191 |
-| test.cs:190:27:190:46 | 13876356431472225791 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:27:190:46 | 13876356431472225791 | 13876356431472225791 |
-| test.cs:190:49:190:68 | 14055243717250701608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:49:190:68 | 14055243717250701608 | 14055243717250701608 |
-| test.cs:191:5:191:24 | 14079676299181301772 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:5:191:24 | 14079676299181301772 | 14079676299181301772 |
-| test.cs:191:27:191:46 | 14095938998438966337 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:27:191:46 | 14095938998438966337 | 14095938998438966337 |
-| test.cs:191:49:191:68 | 14111374107076822891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:49:191:68 | 14111374107076822891 | 14111374107076822891 |
-| test.cs:192:5:192:24 | 14193859431895170587 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:5:192:24 | 14193859431895170587 | 14193859431895170587 |
-| test.cs:192:27:192:46 | 14226582801651130532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:27:192:46 | 14226582801651130532 | 14226582801651130532 |
-| test.cs:192:49:192:68 | 14243671177281069512 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:49:192:68 | 14243671177281069512 | 14243671177281069512 |
-| test.cs:193:5:193:24 | 14256853800858727521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:5:193:24 | 14256853800858727521 | 14256853800858727521 |
-| test.cs:193:27:193:46 | 14480775929210717493 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:27:193:46 | 14480775929210717493 | 14480775929210717493 |
-| test.cs:193:49:193:68 | 14482658293117931546 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:49:193:68 | 14482658293117931546 | 14482658293117931546 |
-| test.cs:194:5:194:24 | 14513577387099045298 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:5:194:24 | 14513577387099045298 | 14513577387099045298 |
-| test.cs:194:27:194:46 | 14630721578341374856 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:27:194:46 | 14630721578341374856 | 14630721578341374856 |
-| test.cs:194:49:194:68 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:49:194:68 | 14695981039346656037 | 14695981039346656037 |
-| test.cs:195:5:195:24 | 14710585101020280896 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:5:195:24 | 14710585101020280896 | 14710585101020280896 |
-| test.cs:195:27:195:45 | 1475579823244607677 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:27:195:45 | 1475579823244607677 | 1475579823244607677 |
-| test.cs:195:48:195:67 | 14868920869169964081 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:48:195:67 | 14868920869169964081 | 14868920869169964081 |
-| test.cs:195:70:195:89 | 14968320160131875803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:70:195:89 | 14968320160131875803 | 14968320160131875803 |
-| test.cs:196:5:196:24 | 14971809093655817917 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:5:196:24 | 14971809093655817917 | 14971809093655817917 |
-| test.cs:196:27:196:46 | 15039834196857999838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:27:196:46 | 15039834196857999838 | 15039834196857999838 |
-| test.cs:196:49:196:68 | 15092207615430402812 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:49:196:68 | 15092207615430402812 | 15092207615430402812 |
-| test.cs:197:5:197:24 | 15114163911481793350 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:5:197:24 | 15114163911481793350 | 15114163911481793350 |
-| test.cs:197:27:197:46 | 15194901817027173566 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:27:197:46 | 15194901817027173566 | 15194901817027173566 |
-| test.cs:197:49:197:68 | 15267980678929160412 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:49:197:68 | 15267980678929160412 | 15267980678929160412 |
-| test.cs:198:5:198:24 | 15457732070353984570 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:5:198:24 | 15457732070353984570 | 15457732070353984570 |
-| test.cs:198:27:198:46 | 15514036435533858158 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:27:198:46 | 15514036435533858158 | 15514036435533858158 |
-| test.cs:198:49:198:68 | 15535773470978271326 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:49:198:68 | 15535773470978271326 | 15535773470978271326 |
-| test.cs:199:5:199:24 | 15587050164583443069 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:5:199:24 | 15587050164583443069 | 15587050164583443069 |
-| test.cs:199:27:199:44 | 155978580751494388 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:27:199:44 | 155978580751494388 | 155978580751494388 |
-| test.cs:199:47:199:66 | 15695338751700748390 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:47:199:66 | 15695338751700748390 | 15695338751700748390 |
-| test.cs:199:69:199:88 | 15997665423159927228 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:69:199:88 | 15997665423159927228 | 15997665423159927228 |
-| test.cs:200:5:200:24 | 16066522799090129502 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:5:200:24 | 16066522799090129502 | 16066522799090129502 |
-| test.cs:200:27:200:46 | 16066651430762394116 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:27:200:46 | 16066651430762394116 | 16066651430762394116 |
-| test.cs:200:49:200:68 | 16112751343173365533 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:49:200:68 | 16112751343173365533 | 16112751343173365533 |
-| test.cs:201:5:201:24 | 16130138450758310172 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:5:201:24 | 16130138450758310172 | 16130138450758310172 |
-| test.cs:201:27:201:45 | 1614465773938842903 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:27:201:45 | 1614465773938842903 | 1614465773938842903 |
-| test.cs:201:48:201:67 | 16292685861617888592 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:48:201:67 | 16292685861617888592 | 16292685861617888592 |
-| test.cs:201:70:201:89 | 16335643316870329598 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:70:201:89 | 16335643316870329598 | 16335643316870329598 |
-| test.cs:202:5:202:24 | 16423314183614230717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:5:202:24 | 16423314183614230717 | 16423314183614230717 |
-| test.cs:202:27:202:46 | 16570804352575357627 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:27:202:46 | 16570804352575357627 | 16570804352575357627 |
-| test.cs:202:49:202:67 | 1682585410644922036 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:49:202:67 | 1682585410644922036 | 1682585410644922036 |
-| test.cs:202:70:202:89 | 16858955978146406642 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:70:202:89 | 16858955978146406642 | 16858955978146406642 |
-| test.cs:203:5:203:24 | 16990567851129491937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:5:203:24 | 16990567851129491937 | 16990567851129491937 |
-| test.cs:203:27:203:46 | 17017923349298346219 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:27:203:46 | 17017923349298346219 | 17017923349298346219 |
-| test.cs:203:49:203:68 | 17097380490166623672 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:49:203:68 | 17097380490166623672 | 17097380490166623672 |
-| test.cs:204:5:204:24 | 17109238199226571972 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:5:204:24 | 17109238199226571972 | 17109238199226571972 |
-| test.cs:204:27:204:46 | 17204844226884380288 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:27:204:46 | 17204844226884380288 | 17204844226884380288 |
-| test.cs:204:49:204:68 | 17291806236368054941 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:49:204:68 | 17291806236368054941 | 17291806236368054941 |
-| test.cs:205:5:205:24 | 17351543633914244545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:5:205:24 | 17351543633914244545 | 17351543633914244545 |
-| test.cs:205:27:205:46 | 17439059603042731363 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:27:205:46 | 17439059603042731363 | 17439059603042731363 |
-| test.cs:205:49:205:68 | 17574002783607647274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:49:205:68 | 17574002783607647274 | 17574002783607647274 |
-| test.cs:206:5:206:24 | 17624147599670377042 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:5:206:24 | 17624147599670377042 | 17624147599670377042 |
-| test.cs:206:27:206:46 | 17633734304611248415 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:27:206:46 | 17633734304611248415 | 17633734304611248415 |
-| test.cs:206:49:206:68 | 17683972236092287897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:49:206:68 | 17683972236092287897 | 17683972236092287897 |
-| test.cs:207:5:207:24 | 17849680105131524334 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:5:207:24 | 17849680105131524334 | 17849680105131524334 |
-| test.cs:207:27:207:46 | 17939405613729073960 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:27:207:46 | 17939405613729073960 | 17939405613729073960 |
-| test.cs:207:49:207:68 | 17956969551821596225 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:49:207:68 | 17956969551821596225 | 17956969551821596225 |
-| test.cs:208:5:208:24 | 17978774977754553159 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:5:208:24 | 17978774977754553159 | 17978774977754553159 |
-| test.cs:208:27:208:46 | 17984632978012874803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:27:208:46 | 17984632978012874803 | 17984632978012874803 |
-| test.cs:208:49:208:68 | 17997967489723066537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:49:208:68 | 17997967489723066537 | 17997967489723066537 |
-| test.cs:209:5:209:24 | 18147627057830191163 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:5:209:24 | 18147627057830191163 | 18147627057830191163 |
-| test.cs:209:27:209:46 | 18150909006539876521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:27:209:46 | 18150909006539876521 | 18150909006539876521 |
-| test.cs:209:49:209:68 | 18159703063075866524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:49:209:68 | 18159703063075866524 | 18159703063075866524 |
-| test.cs:210:5:210:24 | 18246404330670877335 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:5:210:24 | 18246404330670877335 | 18246404330670877335 |
-| test.cs:210:27:210:46 | 18294908219222222902 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:27:210:46 | 18294908219222222902 | 18294908219222222902 |
-| test.cs:210:49:210:68 | 18392881921099771407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:49:210:68 | 18392881921099771407 | 18392881921099771407 |
-| test.cs:211:5:211:24 | 18446744073709551613 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:5:211:24 | 18446744073709551613 | 18446744073709551613 |
-| test.cs:211:27:211:44 | 191060519014405309 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:27:211:44 | 191060519014405309 | 191060519014405309 |
-| test.cs:211:47:211:65 | 2032008861530788751 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:47:211:65 | 2032008861530788751 | 2032008861530788751 |
-| test.cs:211:68:211:86 | 2128122064571842954 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:68:211:86 | 2128122064571842954 | 2128122064571842954 |
-| test.cs:212:5:212:14 | 2147483647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:5:212:14 | 2147483647 | 2147483647 |
-| test.cs:212:17:212:26 | 2147745794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:17:212:26 | 2147745794 | 2147745794 |
-| test.cs:212:29:212:47 | 2380224015317016190 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:29:212:47 | 2380224015317016190 | 2380224015317016190 |
-| test.cs:212:50:212:68 | 2478231962306073784 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:50:212:68 | 2478231962306073784 | 2478231962306073784 |
-| test.cs:213:5:213:23 | 2532538262737333146 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:5:213:23 | 2532538262737333146 | 2532538262737333146 |
-| test.cs:213:26:213:44 | 2589926981877829912 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:26:213:44 | 2589926981877829912 | 2589926981877829912 |
-| test.cs:213:47:213:65 | 2597124982561782591 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:47:213:65 | 2597124982561782591 | 2597124982561782591 |
-| test.cs:213:68:213:86 | 2600364143812063535 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:68:213:86 | 2600364143812063535 | 2600364143812063535 |
-| test.cs:214:5:214:23 | 2717025511528702475 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:5:214:23 | 2717025511528702475 | 2717025511528702475 |
-| test.cs:214:26:214:44 | 2734787258623754862 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:26:214:44 | 2734787258623754862 | 2734787258623754862 |
-| test.cs:214:47:214:63 | 27407921587843457 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:47:214:63 | 27407921587843457 | 27407921587843457 |
-| test.cs:214:66:214:84 | 2760663353550280147 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:66:214:84 | 2760663353550280147 | 2760663353550280147 |
-| test.cs:215:5:215:23 | 2797129108883749491 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:5:215:23 | 2797129108883749491 | 2797129108883749491 |
-| test.cs:215:26:215:44 | 2810460305047003196 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:26:215:44 | 2810460305047003196 | 2810460305047003196 |
-| test.cs:215:47:215:64 | 292198192373389586 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:47:215:64 | 292198192373389586 | 292198192373389586 |
-| test.cs:215:67:215:85 | 2934149816356927366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:67:215:85 | 2934149816356927366 | 2934149816356927366 |
-| test.cs:216:5:216:23 | 3045986759481489935 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:5:216:23 | 3045986759481489935 | 3045986759481489935 |
-| test.cs:216:26:216:44 | 3178468437029279937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:26:216:44 | 3178468437029279937 | 3178468437029279937 |
-| test.cs:216:47:216:65 | 3200333496547938354 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:47:216:65 | 3200333496547938354 | 3200333496547938354 |
-| test.cs:216:68:216:86 | 3320026265773918739 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:68:216:86 | 3320026265773918739 | 3320026265773918739 |
-| test.cs:217:5:217:23 | 3320767229281015341 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:5:217:23 | 3320767229281015341 | 3320767229281015341 |
-| test.cs:217:26:217:44 | 3341747963119755850 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:26:217:44 | 3341747963119755850 | 3341747963119755850 |
-| test.cs:217:47:217:65 | 3407972863931386250 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:47:217:65 | 3407972863931386250 | 3407972863931386250 |
-| test.cs:217:68:217:86 | 3413052607651207697 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:68:217:86 | 3413052607651207697 | 3413052607651207697 |
-| test.cs:218:5:218:23 | 3413886037471417852 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:5:218:23 | 3413886037471417852 | 3413886037471417852 |
-| test.cs:218:26:218:44 | 3421197789791424393 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:26:218:44 | 3421197789791424393 | 3421197789791424393 |
-| test.cs:218:47:218:65 | 3421213182954201407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:47:218:65 | 3421213182954201407 | 3421213182954201407 |
-| test.cs:218:68:218:86 | 3425260965299690882 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:68:218:86 | 3425260965299690882 | 3425260965299690882 |
-| test.cs:219:5:219:23 | 3538022140597504361 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:5:219:23 | 3538022140597504361 | 3538022140597504361 |
-| test.cs:219:26:219:44 | 3575761800716667678 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:26:219:44 | 3575761800716667678 | 3575761800716667678 |
-| test.cs:219:47:219:65 | 3588624367609827560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:47:219:65 | 3588624367609827560 | 3588624367609827560 |
-| test.cs:219:68:219:86 | 3626142665768487764 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:68:219:86 | 3626142665768487764 | 3626142665768487764 |
-| test.cs:220:5:220:23 | 3642525650883269872 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:5:220:23 | 3642525650883269872 | 3642525650883269872 |
-| test.cs:220:26:220:44 | 3656637464651387014 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:26:220:44 | 3656637464651387014 | 3656637464651387014 |
-| test.cs:220:47:220:65 | 3660705254426876796 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:47:220:65 | 3660705254426876796 | 3660705254426876796 |
-| test.cs:220:68:220:86 | 3769837838875367802 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:68:220:86 | 3769837838875367802 | 3769837838875367802 |
-| test.cs:221:5:221:23 | 3778500091710709090 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:5:221:23 | 3778500091710709090 | 3778500091710709090 |
-| test.cs:221:26:221:44 | 3796405623695665524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:26:221:44 | 3796405623695665524 | 3796405623695665524 |
-| test.cs:221:47:221:65 | 3869935012404164040 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:47:221:65 | 3869935012404164040 | 3869935012404164040 |
-| test.cs:221:68:221:86 | 3890769468012566366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:68:221:86 | 3890769468012566366 | 3890769468012566366 |
-| test.cs:222:5:222:23 | 3890794756780010537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:5:222:23 | 3890794756780010537 | 3890794756780010537 |
-| test.cs:222:26:222:43 | 397780960855462669 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:26:222:43 | 397780960855462669 | 397780960855462669 |
-| test.cs:222:46:222:64 | 4030236413975199654 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:46:222:64 | 4030236413975199654 | 4030236413975199654 |
-| test.cs:222:67:222:85 | 4088976323439621041 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:67:222:85 | 4088976323439621041 | 4088976323439621041 |
-| test.cs:223:5:223:23 | 4454255944391929578 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:5:223:23 | 4454255944391929578 | 4454255944391929578 |
-| test.cs:223:26:223:44 | 4501656691368064027 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:26:223:44 | 4501656691368064027 | 4501656691368064027 |
-| test.cs:223:47:223:65 | 4578480846255629462 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:47:223:65 | 4578480846255629462 | 4578480846255629462 |
-| test.cs:223:68:223:86 | 4821863173800309721 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:68:223:86 | 4821863173800309721 | 4821863173800309721 |
-| test.cs:224:5:224:23 | 4931721628717906635 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:5:224:23 | 4931721628717906635 | 4931721628717906635 |
-| test.cs:224:26:224:43 | 506634811745884560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:26:224:43 | 506634811745884560 | 506634811745884560 |
-| test.cs:224:46:224:64 | 5132256620104998637 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:46:224:64 | 5132256620104998637 | 5132256620104998637 |
-| test.cs:224:67:224:85 | 5183687599225757871 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:67:224:85 | 5183687599225757871 | 5183687599225757871 |
-| test.cs:225:5:225:22 | 521157249538507889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:5:225:22 | 521157249538507889 | 521157249538507889 |
-| test.cs:225:25:225:43 | 5219431737322569038 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:25:225:43 | 5219431737322569038 | 5219431737322569038 |
-| test.cs:225:46:225:63 | 541172992193764396 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:46:225:63 | 541172992193764396 | 541172992193764396 |
-| test.cs:225:66:225:84 | 5415426428750045503 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:66:225:84 | 5415426428750045503 | 5415426428750045503 |
-| test.cs:226:5:226:23 | 5449730069165757263 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:5:226:23 | 5449730069165757263 | 5449730069165757263 |
-| test.cs:226:26:226:44 | 5587557070429522647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:26:226:44 | 5587557070429522647 | 5587557070429522647 |
-| test.cs:226:47:226:65 | 5614586596107908838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:47:226:65 | 5614586596107908838 | 5614586596107908838 |
-| test.cs:226:68:226:85 | 576626207276463000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:68:226:85 | 576626207276463000 | 576626207276463000 |
-| test.cs:227:5:227:23 | 5942282052525294911 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:5:227:23 | 5942282052525294911 | 5942282052525294911 |
-| test.cs:227:26:227:44 | 5945487981219695001 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:26:227:44 | 5945487981219695001 | 5945487981219695001 |
-| test.cs:227:47:227:65 | 5984963105389676759 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:47:227:65 | 5984963105389676759 | 5984963105389676759 |
-| test.cs:227:68:227:85 | 607197993339007484 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:68:227:85 | 607197993339007484 | 607197993339007484 |
-| test.cs:228:5:228:23 | 6088115528707848728 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:5:228:23 | 6088115528707848728 | 6088115528707848728 |
-| test.cs:228:26:228:44 | 6116246686670134098 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:26:228:44 | 6116246686670134098 | 6116246686670134098 |
-| test.cs:228:47:228:65 | 6180361713414290679 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:47:228:65 | 6180361713414290679 | 6180361713414290679 |
-| test.cs:228:68:228:86 | 6195833633417633900 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:68:228:86 | 6195833633417633900 | 6195833633417633900 |
-| test.cs:229:5:229:23 | 6274014997237900919 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:5:229:23 | 6274014997237900919 | 6274014997237900919 |
-| test.cs:229:26:229:43 | 640589622539783622 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:26:229:43 | 640589622539783622 | 640589622539783622 |
-| test.cs:229:46:229:64 | 6461429591783621719 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:46:229:64 | 6461429591783621719 | 6461429591783621719 |
-| test.cs:229:67:229:85 | 6491986958834001955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:67:229:85 | 6491986958834001955 | 6491986958834001955 |
-| test.cs:230:5:230:23 | 6508141243778577344 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:5:230:23 | 6508141243778577344 | 6508141243778577344 |
-| test.cs:230:26:230:44 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:26:230:44 | 6605813339339102567 | 6605813339339102567 |
-| test.cs:230:47:230:64 | 682250828679635420 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:47:230:64 | 682250828679635420 | 682250828679635420 |
-| test.cs:230:67:230:85 | 6827032273910657891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:67:230:85 | 6827032273910657891 | 6827032273910657891 |
-| test.cs:231:5:231:23 | 6943102301517884811 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:5:231:23 | 6943102301517884811 | 6943102301517884811 |
-| test.cs:231:26:231:43 | 700598796416086955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:26:231:43 | 700598796416086955 | 700598796416086955 |
-| test.cs:231:46:231:64 | 7080175711202577138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:46:231:64 | 7080175711202577138 | 7080175711202577138 |
-| test.cs:231:67:231:85 | 7175363135479931834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:67:231:85 | 7175363135479931834 | 7175363135479931834 |
-| test.cs:232:5:232:23 | 7315838824213522000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:5:232:23 | 7315838824213522000 | 7315838824213522000 |
-| test.cs:232:26:232:44 | 7412338704062093516 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:26:232:44 | 7412338704062093516 | 7412338704062093516 |
-| test.cs:232:47:232:65 | 7516148236133302073 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:47:232:65 | 7516148236133302073 | 7516148236133302073 |
-| test.cs:232:68:232:86 | 7574774749059321801 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:68:232:86 | 7574774749059321801 | 7574774749059321801 |
-| test.cs:233:5:233:23 | 7701683279824397773 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:5:233:23 | 7701683279824397773 | 7701683279824397773 |
-| test.cs:233:26:233:44 | 7775177810774851294 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:26:233:44 | 7775177810774851294 | 7775177810774851294 |
-| test.cs:233:47:233:65 | 7810436520414958497 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:47:233:65 | 7810436520414958497 | 7810436520414958497 |
-| test.cs:233:68:233:86 | 7878537243757499832 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:68:233:86 | 7878537243757499832 | 7878537243757499832 |
-| test.cs:234:5:234:21 | 79089792725215063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:5:234:21 | 79089792725215063 | 79089792725215063 |
-| test.cs:234:24:234:42 | 7982848972385914508 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:24:234:42 | 7982848972385914508 | 7982848972385914508 |
-| test.cs:234:45:234:63 | 8052533790968282297 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:45:234:63 | 8052533790968282297 | 8052533790968282297 |
-| test.cs:234:66:234:84 | 8129411991672431889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:66:234:84 | 8129411991672431889 | 8129411991672431889 |
-| test.cs:235:5:235:23 | 8146185202538899243 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:5:235:23 | 8146185202538899243 | 8146185202538899243 |
-| test.cs:235:26:235:43 | 835151375515278827 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:26:235:43 | 835151375515278827 | 835151375515278827 |
-| test.cs:235:46:235:64 | 8381292265993977266 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:46:235:64 | 8381292265993977266 | 8381292265993977266 |
-| test.cs:235:67:235:85 | 8408095252303317471 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:67:235:85 | 8408095252303317471 | 8408095252303317471 |
-| test.cs:236:5:236:23 | 8473756179280619170 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:5:236:23 | 8473756179280619170 | 8473756179280619170 |
-| test.cs:236:26:236:44 | 8478833628889826985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:26:236:44 | 8478833628889826985 | 8478833628889826985 |
-| test.cs:236:47:236:65 | 8612208440357175863 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:47:236:65 | 8612208440357175863 | 8612208440357175863 |
-| test.cs:236:68:236:86 | 8697424601205169055 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:68:236:86 | 8697424601205169055 | 8697424601205169055 |
-| test.cs:237:5:237:23 | 8698326794961817906 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:5:237:23 | 8698326794961817906 | 8698326794961817906 |
-| test.cs:237:26:237:44 | 8709004393777297355 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:26:237:44 | 8709004393777297355 | 8709004393777297355 |
-| test.cs:237:47:237:65 | 8727477769544302060 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:47:237:65 | 8727477769544302060 | 8727477769544302060 |
-| test.cs:237:68:237:86 | 8760312338504300643 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:68:237:86 | 8760312338504300643 | 8760312338504300643 |
-| test.cs:238:5:238:23 | 8799118153397725683 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:5:238:23 | 8799118153397725683 | 8799118153397725683 |
-| test.cs:238:26:238:44 | 8873858923435176895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:26:238:44 | 8873858923435176895 | 8873858923435176895 |
-| test.cs:238:47:238:65 | 8994091295115840290 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:47:238:65 | 8994091295115840290 | 8994091295115840290 |
-| test.cs:238:68:238:86 | 9007106680104765185 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:68:238:86 | 9007106680104765185 | 9007106680104765185 |
-| test.cs:239:5:239:23 | 9061219083560670602 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:5:239:23 | 9061219083560670602 | 9061219083560670602 |
-| test.cs:239:26:239:44 | 9149947745824492274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:26:239:44 | 9149947745824492274 | 9149947745824492274 |
-| test.cs:239:47:239:64 | 917638920165491138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:47:239:64 | 917638920165491138 | 917638920165491138 |
-| test.cs:239:67:239:85 | 9234894663364701749 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:67:239:85 | 9234894663364701749 | 9234894663364701749 |
-| test.cs:240:5:240:23 | 9333057603143916814 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:5:240:23 | 9333057603143916814 | 9333057603143916814 |
-| test.cs:240:26:240:44 | 9384605490088500348 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:26:240:44 | 9384605490088500348 | 9384605490088500348 |
-| test.cs:240:47:240:65 | 9531326785919727076 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:47:240:65 | 9531326785919727076 | 9531326785919727076 |
-| test.cs:240:68:240:86 | 9555688264681862794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:68:240:86 | 9555688264681862794 | 9555688264681862794 |
-| test.cs:241:5:241:23 | 9559632696372799208 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:241:5:241:23 | 9559632696372799208 | 9559632696372799208 |
-| test.cs:241:26:241:44 | 9903758755917170407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:241:26:241:44 | 9903758755917170407 | 9903758755917170407 |
+| test.cs:9:15:9:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:9:15:9:36 | 14695981039346656037 | 14695981039346656037 |
+| test.cs:14:11:14:25 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:14:11:14:25 | 1099511628211 | 1099511628211 |
+| test.cs:25:15:25:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:25:15:25:36 | 14695981039346656037 | 14695981039346656037 |
+| test.cs:31:12:31:26 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:31:12:31:26 | 1099511628211 | 1099511628211 |
+| test.cs:39:16:39:36 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:39:16:39:36 | 6605813339339102567 | 6605813339339102567 |
+| test.cs:172:5:172:24 | 10063651499895178962 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:172:5:172:24 | 10063651499895178962 | 10063651499895178962 |
+| test.cs:172:27:172:46 | 10235971842993272939 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:172:27:172:46 | 10235971842993272939 | 10235971842993272939 |
+| test.cs:172:49:172:68 | 10296494671777307979 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:172:49:172:68 | 10296494671777307979 | 10296494671777307979 |
+| test.cs:173:5:173:24 | 10336842116636872171 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:5:173:24 | 10336842116636872171 | 10336842116636872171 |
+| test.cs:173:27:173:46 | 10374841591685794123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:27:173:46 | 10374841591685794123 | 10374841591685794123 |
+| test.cs:173:49:173:68 | 10393903804869831898 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:49:173:68 | 10393903804869831898 | 10393903804869831898 |
+| test.cs:174:5:174:24 | 10463926208560207521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:5:174:24 | 10463926208560207521 | 10463926208560207521 |
+| test.cs:174:27:174:46 | 10484659978517092504 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:27:174:46 | 10484659978517092504 | 10484659978517092504 |
+| test.cs:174:49:174:68 | 10501212300031893463 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:49:174:68 | 10501212300031893463 | 10501212300031893463 |
+| test.cs:175:5:175:24 | 10545868833523019926 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:5:175:24 | 10545868833523019926 | 10545868833523019926 |
+| test.cs:175:27:175:46 | 10657751674541025650 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:27:175:46 | 10657751674541025650 | 10657751674541025650 |
+| test.cs:175:49:175:66 | 106672141413120087 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:49:175:66 | 106672141413120087 | 106672141413120087 |
+| test.cs:175:69:175:88 | 10734127004244879770 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:69:175:88 | 10734127004244879770 | 10734127004244879770 |
+| test.cs:176:5:176:24 | 10829648878147112121 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:5:176:24 | 10829648878147112121 | 10829648878147112121 |
+| test.cs:176:27:176:39 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:27:176:39 | 1099511628211 | 1099511628211 |
+| test.cs:176:42:176:61 | 11073283311104541690 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:42:176:61 | 11073283311104541690 | 11073283311104541690 |
+| test.cs:176:64:176:82 | 1109067043404435916 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:64:176:82 | 1109067043404435916 | 1109067043404435916 |
+| test.cs:177:5:177:24 | 11109294216876344399 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:5:177:24 | 11109294216876344399 | 11109294216876344399 |
+| test.cs:177:27:177:46 | 11266044540366291518 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:27:177:46 | 11266044540366291518 | 11266044540366291518 |
+| test.cs:177:49:177:68 | 11385275378891906608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:49:177:68 | 11385275378891906608 | 11385275378891906608 |
+| test.cs:178:5:178:24 | 11771945869106552231 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:5:178:24 | 11771945869106552231 | 11771945869106552231 |
+| test.cs:178:27:178:46 | 11801746708619571308 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:27:178:46 | 11801746708619571308 | 11801746708619571308 |
+| test.cs:178:49:178:68 | 11818825521849580123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:49:178:68 | 11818825521849580123 | 11818825521849580123 |
+| test.cs:179:5:179:24 | 11913842725949116895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:5:179:24 | 11913842725949116895 | 11913842725949116895 |
+| test.cs:179:27:179:46 | 12027963942392743532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:27:179:46 | 12027963942392743532 | 12027963942392743532 |
+| test.cs:179:49:179:68 | 12094027092655598256 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:49:179:68 | 12094027092655598256 | 12094027092655598256 |
+| test.cs:180:5:180:24 | 12343334044036541897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:5:180:24 | 12343334044036541897 | 12343334044036541897 |
+| test.cs:180:27:180:46 | 12445177985737237804 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:27:180:46 | 12445177985737237804 | 12445177985737237804 |
+| test.cs:180:49:180:68 | 12445232961318634374 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:49:180:68 | 12445232961318634374 | 12445232961318634374 |
+| test.cs:181:5:181:24 | 12574535824074203265 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:5:181:24 | 12574535824074203265 | 12574535824074203265 |
+| test.cs:181:27:181:46 | 12679195163651834776 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:27:181:46 | 12679195163651834776 | 12679195163651834776 |
+| test.cs:181:49:181:68 | 12709986806548166638 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:49:181:68 | 12709986806548166638 | 12709986806548166638 |
+| test.cs:182:5:182:24 | 12718416789200275332 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:5:182:24 | 12718416789200275332 | 12718416789200275332 |
+| test.cs:182:27:182:46 | 12785322942775634499 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:27:182:46 | 12785322942775634499 | 12785322942775634499 |
+| test.cs:182:49:182:68 | 12790084614253405985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:49:182:68 | 12790084614253405985 | 12790084614253405985 |
+| test.cs:183:5:183:24 | 12969190449276002545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:5:183:24 | 12969190449276002545 | 12969190449276002545 |
+| test.cs:183:27:183:46 | 13014156621614176974 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:27:183:46 | 13014156621614176974 | 13014156621614176974 |
+| test.cs:183:49:183:68 | 13029357933491444455 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:49:183:68 | 13029357933491444455 | 13029357933491444455 |
+| test.cs:184:5:184:24 | 13135068273077306806 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:5:184:24 | 13135068273077306806 | 13135068273077306806 |
+| test.cs:184:27:184:46 | 13260224381505715848 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:27:184:46 | 13260224381505715848 | 13260224381505715848 |
+| test.cs:184:49:184:68 | 13316211011159594063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:49:184:68 | 13316211011159594063 | 13316211011159594063 |
+| test.cs:185:5:185:24 | 13464308873961738403 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:5:185:24 | 13464308873961738403 | 13464308873961738403 |
+| test.cs:185:27:185:46 | 13544031715334011032 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:27:185:46 | 13544031715334011032 | 13544031715334011032 |
+| test.cs:185:49:185:68 | 13581776705111912829 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:49:185:68 | 13581776705111912829 | 13581776705111912829 |
+| test.cs:186:5:186:24 | 13599785766252827703 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:5:186:24 | 13599785766252827703 | 13599785766252827703 |
+| test.cs:186:27:186:46 | 13611051401579634621 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:27:186:46 | 13611051401579634621 | 13611051401579634621 |
+| test.cs:186:49:186:68 | 13611814135072561278 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:49:186:68 | 13611814135072561278 | 13611814135072561278 |
+| test.cs:187:5:187:24 | 13655261125244647696 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:5:187:24 | 13655261125244647696 | 13655261125244647696 |
+| test.cs:187:27:187:45 | 1367627386496056834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:27:187:45 | 1367627386496056834 | 1367627386496056834 |
+| test.cs:187:48:187:66 | 1368907909245890092 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:48:187:66 | 1368907909245890092 | 1368907909245890092 |
+| test.cs:187:69:187:88 | 13693525876560827283 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:69:187:88 | 13693525876560827283 | 13693525876560827283 |
+| test.cs:188:5:188:24 | 13783346438774742614 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:5:188:24 | 13783346438774742614 | 13783346438774742614 |
+| test.cs:188:27:188:46 | 13799353263187722717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:27:188:46 | 13799353263187722717 | 13799353263187722717 |
+| test.cs:188:49:188:68 | 13825071784440082496 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:49:188:68 | 13825071784440082496 | 13825071784440082496 |
+| test.cs:189:5:189:24 | 13852439084267373191 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:5:189:24 | 13852439084267373191 | 13852439084267373191 |
+| test.cs:189:27:189:46 | 13876356431472225791 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:27:189:46 | 13876356431472225791 | 13876356431472225791 |
+| test.cs:189:49:189:68 | 14055243717250701608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:49:189:68 | 14055243717250701608 | 14055243717250701608 |
+| test.cs:190:5:190:24 | 14079676299181301772 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:5:190:24 | 14079676299181301772 | 14079676299181301772 |
+| test.cs:190:27:190:46 | 14095938998438966337 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:27:190:46 | 14095938998438966337 | 14095938998438966337 |
+| test.cs:190:49:190:68 | 14111374107076822891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:49:190:68 | 14111374107076822891 | 14111374107076822891 |
+| test.cs:191:5:191:24 | 14193859431895170587 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:5:191:24 | 14193859431895170587 | 14193859431895170587 |
+| test.cs:191:27:191:46 | 14226582801651130532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:27:191:46 | 14226582801651130532 | 14226582801651130532 |
+| test.cs:191:49:191:68 | 14243671177281069512 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:49:191:68 | 14243671177281069512 | 14243671177281069512 |
+| test.cs:192:5:192:24 | 14256853800858727521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:5:192:24 | 14256853800858727521 | 14256853800858727521 |
+| test.cs:192:27:192:46 | 14480775929210717493 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:27:192:46 | 14480775929210717493 | 14480775929210717493 |
+| test.cs:192:49:192:68 | 14482658293117931546 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:49:192:68 | 14482658293117931546 | 14482658293117931546 |
+| test.cs:193:5:193:24 | 14513577387099045298 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:5:193:24 | 14513577387099045298 | 14513577387099045298 |
+| test.cs:193:27:193:46 | 14630721578341374856 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:27:193:46 | 14630721578341374856 | 14630721578341374856 |
+| test.cs:193:49:193:68 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:49:193:68 | 14695981039346656037 | 14695981039346656037 |
+| test.cs:194:5:194:24 | 14710585101020280896 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:5:194:24 | 14710585101020280896 | 14710585101020280896 |
+| test.cs:194:27:194:45 | 1475579823244607677 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:27:194:45 | 1475579823244607677 | 1475579823244607677 |
+| test.cs:194:48:194:67 | 14868920869169964081 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:48:194:67 | 14868920869169964081 | 14868920869169964081 |
+| test.cs:194:70:194:89 | 14968320160131875803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:70:194:89 | 14968320160131875803 | 14968320160131875803 |
+| test.cs:195:5:195:24 | 14971809093655817917 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:5:195:24 | 14971809093655817917 | 14971809093655817917 |
+| test.cs:195:27:195:46 | 15039834196857999838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:27:195:46 | 15039834196857999838 | 15039834196857999838 |
+| test.cs:195:49:195:68 | 15092207615430402812 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:49:195:68 | 15092207615430402812 | 15092207615430402812 |
+| test.cs:196:5:196:24 | 15114163911481793350 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:5:196:24 | 15114163911481793350 | 15114163911481793350 |
+| test.cs:196:27:196:46 | 15194901817027173566 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:27:196:46 | 15194901817027173566 | 15194901817027173566 |
+| test.cs:196:49:196:68 | 15267980678929160412 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:49:196:68 | 15267980678929160412 | 15267980678929160412 |
+| test.cs:197:5:197:24 | 15457732070353984570 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:5:197:24 | 15457732070353984570 | 15457732070353984570 |
+| test.cs:197:27:197:46 | 15514036435533858158 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:27:197:46 | 15514036435533858158 | 15514036435533858158 |
+| test.cs:197:49:197:68 | 15535773470978271326 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:49:197:68 | 15535773470978271326 | 15535773470978271326 |
+| test.cs:198:5:198:24 | 15587050164583443069 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:5:198:24 | 15587050164583443069 | 15587050164583443069 |
+| test.cs:198:27:198:44 | 155978580751494388 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:27:198:44 | 155978580751494388 | 155978580751494388 |
+| test.cs:198:47:198:66 | 15695338751700748390 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:47:198:66 | 15695338751700748390 | 15695338751700748390 |
+| test.cs:198:69:198:88 | 15997665423159927228 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:69:198:88 | 15997665423159927228 | 15997665423159927228 |
+| test.cs:199:5:199:24 | 16066522799090129502 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:5:199:24 | 16066522799090129502 | 16066522799090129502 |
+| test.cs:199:27:199:46 | 16066651430762394116 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:27:199:46 | 16066651430762394116 | 16066651430762394116 |
+| test.cs:199:49:199:68 | 16112751343173365533 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:49:199:68 | 16112751343173365533 | 16112751343173365533 |
+| test.cs:200:5:200:24 | 16130138450758310172 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:5:200:24 | 16130138450758310172 | 16130138450758310172 |
+| test.cs:200:27:200:45 | 1614465773938842903 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:27:200:45 | 1614465773938842903 | 1614465773938842903 |
+| test.cs:200:48:200:67 | 16292685861617888592 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:48:200:67 | 16292685861617888592 | 16292685861617888592 |
+| test.cs:200:70:200:89 | 16335643316870329598 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:70:200:89 | 16335643316870329598 | 16335643316870329598 |
+| test.cs:201:5:201:24 | 16423314183614230717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:5:201:24 | 16423314183614230717 | 16423314183614230717 |
+| test.cs:201:27:201:46 | 16570804352575357627 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:27:201:46 | 16570804352575357627 | 16570804352575357627 |
+| test.cs:201:49:201:67 | 1682585410644922036 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:49:201:67 | 1682585410644922036 | 1682585410644922036 |
+| test.cs:201:70:201:89 | 16858955978146406642 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:70:201:89 | 16858955978146406642 | 16858955978146406642 |
+| test.cs:202:5:202:24 | 16990567851129491937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:5:202:24 | 16990567851129491937 | 16990567851129491937 |
+| test.cs:202:27:202:46 | 17017923349298346219 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:27:202:46 | 17017923349298346219 | 17017923349298346219 |
+| test.cs:202:49:202:68 | 17097380490166623672 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:49:202:68 | 17097380490166623672 | 17097380490166623672 |
+| test.cs:203:5:203:24 | 17109238199226571972 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:5:203:24 | 17109238199226571972 | 17109238199226571972 |
+| test.cs:203:27:203:46 | 17204844226884380288 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:27:203:46 | 17204844226884380288 | 17204844226884380288 |
+| test.cs:203:49:203:68 | 17291806236368054941 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:49:203:68 | 17291806236368054941 | 17291806236368054941 |
+| test.cs:204:5:204:24 | 17351543633914244545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:5:204:24 | 17351543633914244545 | 17351543633914244545 |
+| test.cs:204:27:204:46 | 17439059603042731363 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:27:204:46 | 17439059603042731363 | 17439059603042731363 |
+| test.cs:204:49:204:68 | 17574002783607647274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:49:204:68 | 17574002783607647274 | 17574002783607647274 |
+| test.cs:205:5:205:24 | 17624147599670377042 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:5:205:24 | 17624147599670377042 | 17624147599670377042 |
+| test.cs:205:27:205:46 | 17633734304611248415 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:27:205:46 | 17633734304611248415 | 17633734304611248415 |
+| test.cs:205:49:205:68 | 17683972236092287897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:49:205:68 | 17683972236092287897 | 17683972236092287897 |
+| test.cs:206:5:206:24 | 17849680105131524334 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:5:206:24 | 17849680105131524334 | 17849680105131524334 |
+| test.cs:206:27:206:46 | 17939405613729073960 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:27:206:46 | 17939405613729073960 | 17939405613729073960 |
+| test.cs:206:49:206:68 | 17956969551821596225 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:49:206:68 | 17956969551821596225 | 17956969551821596225 |
+| test.cs:207:5:207:24 | 17978774977754553159 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:5:207:24 | 17978774977754553159 | 17978774977754553159 |
+| test.cs:207:27:207:46 | 17984632978012874803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:27:207:46 | 17984632978012874803 | 17984632978012874803 |
+| test.cs:207:49:207:68 | 17997967489723066537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:49:207:68 | 17997967489723066537 | 17997967489723066537 |
+| test.cs:208:5:208:24 | 18147627057830191163 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:5:208:24 | 18147627057830191163 | 18147627057830191163 |
+| test.cs:208:27:208:46 | 18150909006539876521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:27:208:46 | 18150909006539876521 | 18150909006539876521 |
+| test.cs:208:49:208:68 | 18159703063075866524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:49:208:68 | 18159703063075866524 | 18159703063075866524 |
+| test.cs:209:5:209:24 | 18246404330670877335 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:5:209:24 | 18246404330670877335 | 18246404330670877335 |
+| test.cs:209:27:209:46 | 18294908219222222902 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:27:209:46 | 18294908219222222902 | 18294908219222222902 |
+| test.cs:209:49:209:68 | 18392881921099771407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:49:209:68 | 18392881921099771407 | 18392881921099771407 |
+| test.cs:210:5:210:24 | 18446744073709551613 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:5:210:24 | 18446744073709551613 | 18446744073709551613 |
+| test.cs:210:27:210:44 | 191060519014405309 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:27:210:44 | 191060519014405309 | 191060519014405309 |
+| test.cs:210:47:210:65 | 2032008861530788751 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:47:210:65 | 2032008861530788751 | 2032008861530788751 |
+| test.cs:210:68:210:86 | 2128122064571842954 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:68:210:86 | 2128122064571842954 | 2128122064571842954 |
+| test.cs:211:5:211:14 | 2147483647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:5:211:14 | 2147483647 | 2147483647 |
+| test.cs:211:17:211:26 | 2147745794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:17:211:26 | 2147745794 | 2147745794 |
+| test.cs:211:29:211:47 | 2380224015317016190 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:29:211:47 | 2380224015317016190 | 2380224015317016190 |
+| test.cs:211:50:211:68 | 2478231962306073784 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:50:211:68 | 2478231962306073784 | 2478231962306073784 |
+| test.cs:212:5:212:23 | 2532538262737333146 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:5:212:23 | 2532538262737333146 | 2532538262737333146 |
+| test.cs:212:26:212:44 | 2589926981877829912 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:26:212:44 | 2589926981877829912 | 2589926981877829912 |
+| test.cs:212:47:212:65 | 2597124982561782591 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:47:212:65 | 2597124982561782591 | 2597124982561782591 |
+| test.cs:212:68:212:86 | 2600364143812063535 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:68:212:86 | 2600364143812063535 | 2600364143812063535 |
+| test.cs:213:5:213:23 | 2717025511528702475 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:5:213:23 | 2717025511528702475 | 2717025511528702475 |
+| test.cs:213:26:213:44 | 2734787258623754862 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:26:213:44 | 2734787258623754862 | 2734787258623754862 |
+| test.cs:213:47:213:63 | 27407921587843457 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:47:213:63 | 27407921587843457 | 27407921587843457 |
+| test.cs:213:66:213:84 | 2760663353550280147 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:66:213:84 | 2760663353550280147 | 2760663353550280147 |
+| test.cs:214:5:214:23 | 2797129108883749491 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:5:214:23 | 2797129108883749491 | 2797129108883749491 |
+| test.cs:214:26:214:44 | 2810460305047003196 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:26:214:44 | 2810460305047003196 | 2810460305047003196 |
+| test.cs:214:47:214:64 | 292198192373389586 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:47:214:64 | 292198192373389586 | 292198192373389586 |
+| test.cs:214:67:214:85 | 2934149816356927366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:67:214:85 | 2934149816356927366 | 2934149816356927366 |
+| test.cs:215:5:215:23 | 3045986759481489935 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:5:215:23 | 3045986759481489935 | 3045986759481489935 |
+| test.cs:215:26:215:44 | 3178468437029279937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:26:215:44 | 3178468437029279937 | 3178468437029279937 |
+| test.cs:215:47:215:65 | 3200333496547938354 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:47:215:65 | 3200333496547938354 | 3200333496547938354 |
+| test.cs:215:68:215:86 | 3320026265773918739 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:68:215:86 | 3320026265773918739 | 3320026265773918739 |
+| test.cs:216:5:216:23 | 3320767229281015341 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:5:216:23 | 3320767229281015341 | 3320767229281015341 |
+| test.cs:216:26:216:44 | 3341747963119755850 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:26:216:44 | 3341747963119755850 | 3341747963119755850 |
+| test.cs:216:47:216:65 | 3407972863931386250 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:47:216:65 | 3407972863931386250 | 3407972863931386250 |
+| test.cs:216:68:216:86 | 3413052607651207697 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:68:216:86 | 3413052607651207697 | 3413052607651207697 |
+| test.cs:217:5:217:23 | 3413886037471417852 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:5:217:23 | 3413886037471417852 | 3413886037471417852 |
+| test.cs:217:26:217:44 | 3421197789791424393 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:26:217:44 | 3421197789791424393 | 3421197789791424393 |
+| test.cs:217:47:217:65 | 3421213182954201407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:47:217:65 | 3421213182954201407 | 3421213182954201407 |
+| test.cs:217:68:217:86 | 3425260965299690882 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:68:217:86 | 3425260965299690882 | 3425260965299690882 |
+| test.cs:218:5:218:23 | 3538022140597504361 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:5:218:23 | 3538022140597504361 | 3538022140597504361 |
+| test.cs:218:26:218:44 | 3575761800716667678 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:26:218:44 | 3575761800716667678 | 3575761800716667678 |
+| test.cs:218:47:218:65 | 3588624367609827560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:47:218:65 | 3588624367609827560 | 3588624367609827560 |
+| test.cs:218:68:218:86 | 3626142665768487764 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:68:218:86 | 3626142665768487764 | 3626142665768487764 |
+| test.cs:219:5:219:23 | 3642525650883269872 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:5:219:23 | 3642525650883269872 | 3642525650883269872 |
+| test.cs:219:26:219:44 | 3656637464651387014 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:26:219:44 | 3656637464651387014 | 3656637464651387014 |
+| test.cs:219:47:219:65 | 3660705254426876796 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:47:219:65 | 3660705254426876796 | 3660705254426876796 |
+| test.cs:219:68:219:86 | 3769837838875367802 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:68:219:86 | 3769837838875367802 | 3769837838875367802 |
+| test.cs:220:5:220:23 | 3778500091710709090 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:5:220:23 | 3778500091710709090 | 3778500091710709090 |
+| test.cs:220:26:220:44 | 3796405623695665524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:26:220:44 | 3796405623695665524 | 3796405623695665524 |
+| test.cs:220:47:220:65 | 3869935012404164040 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:47:220:65 | 3869935012404164040 | 3869935012404164040 |
+| test.cs:220:68:220:86 | 3890769468012566366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:68:220:86 | 3890769468012566366 | 3890769468012566366 |
+| test.cs:221:5:221:23 | 3890794756780010537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:5:221:23 | 3890794756780010537 | 3890794756780010537 |
+| test.cs:221:26:221:43 | 397780960855462669 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:26:221:43 | 397780960855462669 | 397780960855462669 |
+| test.cs:221:46:221:64 | 4030236413975199654 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:46:221:64 | 4030236413975199654 | 4030236413975199654 |
+| test.cs:221:67:221:85 | 4088976323439621041 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:67:221:85 | 4088976323439621041 | 4088976323439621041 |
+| test.cs:222:5:222:23 | 4454255944391929578 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:5:222:23 | 4454255944391929578 | 4454255944391929578 |
+| test.cs:222:26:222:44 | 4501656691368064027 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:26:222:44 | 4501656691368064027 | 4501656691368064027 |
+| test.cs:222:47:222:65 | 4578480846255629462 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:47:222:65 | 4578480846255629462 | 4578480846255629462 |
+| test.cs:222:68:222:86 | 4821863173800309721 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:68:222:86 | 4821863173800309721 | 4821863173800309721 |
+| test.cs:223:5:223:23 | 4931721628717906635 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:5:223:23 | 4931721628717906635 | 4931721628717906635 |
+| test.cs:223:26:223:43 | 506634811745884560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:26:223:43 | 506634811745884560 | 506634811745884560 |
+| test.cs:223:46:223:64 | 5132256620104998637 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:46:223:64 | 5132256620104998637 | 5132256620104998637 |
+| test.cs:223:67:223:85 | 5183687599225757871 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:67:223:85 | 5183687599225757871 | 5183687599225757871 |
+| test.cs:224:5:224:22 | 521157249538507889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:5:224:22 | 521157249538507889 | 521157249538507889 |
+| test.cs:224:25:224:43 | 5219431737322569038 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:25:224:43 | 5219431737322569038 | 5219431737322569038 |
+| test.cs:224:46:224:63 | 541172992193764396 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:46:224:63 | 541172992193764396 | 541172992193764396 |
+| test.cs:224:66:224:84 | 5415426428750045503 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:66:224:84 | 5415426428750045503 | 5415426428750045503 |
+| test.cs:225:5:225:23 | 5449730069165757263 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:5:225:23 | 5449730069165757263 | 5449730069165757263 |
+| test.cs:225:26:225:44 | 5587557070429522647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:26:225:44 | 5587557070429522647 | 5587557070429522647 |
+| test.cs:225:47:225:65 | 5614586596107908838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:47:225:65 | 5614586596107908838 | 5614586596107908838 |
+| test.cs:225:68:225:85 | 576626207276463000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:68:225:85 | 576626207276463000 | 576626207276463000 |
+| test.cs:226:5:226:23 | 5942282052525294911 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:5:226:23 | 5942282052525294911 | 5942282052525294911 |
+| test.cs:226:26:226:44 | 5945487981219695001 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:26:226:44 | 5945487981219695001 | 5945487981219695001 |
+| test.cs:226:47:226:65 | 5984963105389676759 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:47:226:65 | 5984963105389676759 | 5984963105389676759 |
+| test.cs:226:68:226:85 | 607197993339007484 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:68:226:85 | 607197993339007484 | 607197993339007484 |
+| test.cs:227:5:227:23 | 6088115528707848728 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:5:227:23 | 6088115528707848728 | 6088115528707848728 |
+| test.cs:227:26:227:44 | 6116246686670134098 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:26:227:44 | 6116246686670134098 | 6116246686670134098 |
+| test.cs:227:47:227:65 | 6180361713414290679 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:47:227:65 | 6180361713414290679 | 6180361713414290679 |
+| test.cs:227:68:227:86 | 6195833633417633900 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:68:227:86 | 6195833633417633900 | 6195833633417633900 |
+| test.cs:228:5:228:23 | 6274014997237900919 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:5:228:23 | 6274014997237900919 | 6274014997237900919 |
+| test.cs:228:26:228:43 | 640589622539783622 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:26:228:43 | 640589622539783622 | 640589622539783622 |
+| test.cs:228:46:228:64 | 6461429591783621719 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:46:228:64 | 6461429591783621719 | 6461429591783621719 |
+| test.cs:228:67:228:85 | 6491986958834001955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:67:228:85 | 6491986958834001955 | 6491986958834001955 |
+| test.cs:229:5:229:23 | 6508141243778577344 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:5:229:23 | 6508141243778577344 | 6508141243778577344 |
+| test.cs:229:26:229:44 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:26:229:44 | 6605813339339102567 | 6605813339339102567 |
+| test.cs:229:47:229:64 | 682250828679635420 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:47:229:64 | 682250828679635420 | 682250828679635420 |
+| test.cs:229:67:229:85 | 6827032273910657891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:67:229:85 | 6827032273910657891 | 6827032273910657891 |
+| test.cs:230:5:230:23 | 6943102301517884811 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:5:230:23 | 6943102301517884811 | 6943102301517884811 |
+| test.cs:230:26:230:43 | 700598796416086955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:26:230:43 | 700598796416086955 | 700598796416086955 |
+| test.cs:230:46:230:64 | 7080175711202577138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:46:230:64 | 7080175711202577138 | 7080175711202577138 |
+| test.cs:230:67:230:85 | 7175363135479931834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:67:230:85 | 7175363135479931834 | 7175363135479931834 |
+| test.cs:231:5:231:23 | 7315838824213522000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:5:231:23 | 7315838824213522000 | 7315838824213522000 |
+| test.cs:231:26:231:44 | 7412338704062093516 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:26:231:44 | 7412338704062093516 | 7412338704062093516 |
+| test.cs:231:47:231:65 | 7516148236133302073 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:47:231:65 | 7516148236133302073 | 7516148236133302073 |
+| test.cs:231:68:231:86 | 7574774749059321801 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:68:231:86 | 7574774749059321801 | 7574774749059321801 |
+| test.cs:232:5:232:23 | 7701683279824397773 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:5:232:23 | 7701683279824397773 | 7701683279824397773 |
+| test.cs:232:26:232:44 | 7775177810774851294 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:26:232:44 | 7775177810774851294 | 7775177810774851294 |
+| test.cs:232:47:232:65 | 7810436520414958497 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:47:232:65 | 7810436520414958497 | 7810436520414958497 |
+| test.cs:232:68:232:86 | 7878537243757499832 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:68:232:86 | 7878537243757499832 | 7878537243757499832 |
+| test.cs:233:5:233:21 | 79089792725215063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:5:233:21 | 79089792725215063 | 79089792725215063 |
+| test.cs:233:24:233:42 | 7982848972385914508 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:24:233:42 | 7982848972385914508 | 7982848972385914508 |
+| test.cs:233:45:233:63 | 8052533790968282297 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:45:233:63 | 8052533790968282297 | 8052533790968282297 |
+| test.cs:233:66:233:84 | 8129411991672431889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:66:233:84 | 8129411991672431889 | 8129411991672431889 |
+| test.cs:234:5:234:23 | 8146185202538899243 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:5:234:23 | 8146185202538899243 | 8146185202538899243 |
+| test.cs:234:26:234:43 | 835151375515278827 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:26:234:43 | 835151375515278827 | 835151375515278827 |
+| test.cs:234:46:234:64 | 8381292265993977266 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:46:234:64 | 8381292265993977266 | 8381292265993977266 |
+| test.cs:234:67:234:85 | 8408095252303317471 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:67:234:85 | 8408095252303317471 | 8408095252303317471 |
+| test.cs:235:5:235:23 | 8473756179280619170 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:5:235:23 | 8473756179280619170 | 8473756179280619170 |
+| test.cs:235:26:235:44 | 8478833628889826985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:26:235:44 | 8478833628889826985 | 8478833628889826985 |
+| test.cs:235:47:235:65 | 8612208440357175863 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:47:235:65 | 8612208440357175863 | 8612208440357175863 |
+| test.cs:235:68:235:86 | 8697424601205169055 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:68:235:86 | 8697424601205169055 | 8697424601205169055 |
+| test.cs:236:5:236:23 | 8698326794961817906 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:5:236:23 | 8698326794961817906 | 8698326794961817906 |
+| test.cs:236:26:236:44 | 8709004393777297355 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:26:236:44 | 8709004393777297355 | 8709004393777297355 |
+| test.cs:236:47:236:65 | 8727477769544302060 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:47:236:65 | 8727477769544302060 | 8727477769544302060 |
+| test.cs:236:68:236:86 | 8760312338504300643 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:68:236:86 | 8760312338504300643 | 8760312338504300643 |
+| test.cs:237:5:237:23 | 8799118153397725683 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:5:237:23 | 8799118153397725683 | 8799118153397725683 |
+| test.cs:237:26:237:44 | 8873858923435176895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:26:237:44 | 8873858923435176895 | 8873858923435176895 |
+| test.cs:237:47:237:65 | 8994091295115840290 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:47:237:65 | 8994091295115840290 | 8994091295115840290 |
+| test.cs:237:68:237:86 | 9007106680104765185 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:68:237:86 | 9007106680104765185 | 9007106680104765185 |
+| test.cs:238:5:238:23 | 9061219083560670602 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:5:238:23 | 9061219083560670602 | 9061219083560670602 |
+| test.cs:238:26:238:44 | 9149947745824492274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:26:238:44 | 9149947745824492274 | 9149947745824492274 |
+| test.cs:238:47:238:64 | 917638920165491138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:47:238:64 | 917638920165491138 | 917638920165491138 |
+| test.cs:238:67:238:85 | 9234894663364701749 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:67:238:85 | 9234894663364701749 | 9234894663364701749 |
+| test.cs:239:5:239:23 | 9333057603143916814 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:5:239:23 | 9333057603143916814 | 9333057603143916814 |
+| test.cs:239:26:239:44 | 9384605490088500348 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:26:239:44 | 9384605490088500348 | 9384605490088500348 |
+| test.cs:239:47:239:65 | 9531326785919727076 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:47:239:65 | 9531326785919727076 | 9531326785919727076 |
+| test.cs:239:68:239:86 | 9555688264681862794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:68:239:86 | 9555688264681862794 | 9555688264681862794 |
+| test.cs:240:5:240:23 | 9559632696372799208 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:5:240:23 | 9559632696372799208 | 9559632696372799208 |
+| test.cs:240:26:240:44 | 9903758755917170407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:26:240:44 | 9903758755917170407 | 9903758755917170407 |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected
index 043068419d7..1f6886a8a91 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected
@@ -1,140 +1,140 @@
-| test.cs:247:4:247:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:4:247:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | (?i)([^a-z]\|^)(test)([^a-z]\|$) |
-| test.cs:247:38:247:55 | "(?i)(solarwinds)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:38:247:55 | "(?i)(solarwinds)" | (?i)(solarwinds) |
-| test.cs:247:58:247:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:58:247:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | [{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n |
-| test.cs:248:4:248:18 | "[{0,5}] {1}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:4:248:18 | "[{0,5}] {1}\n" | [{0,5}] {1}\n |
-| test.cs:248:21:248:37 | "[E] {0} {1} {2}" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:21:248:37 | "[E] {0} {1} {2}" | [E] {0} {1} {2} |
-| test.cs:249:4:249:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:4:249:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | "\\{[0-9a-f-]{36}\\}"\|"[0-9a-f]{32}"\|"[0-9a-f]{16}" |
-| test.cs:249:65:249:79 | ".CortexPlugin" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:65:249:79 | ".CortexPlugin" | .CortexPlugin |
-| test.cs:249:82:249:89 | ".Orion" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:82:249:89 | ".Orion" | .Orion |
-| test.cs:250:4:250:36 | "\\"EventName\\":\\"EventManager\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:250:4:250:36 | "\\"EventName\\":\\"EventManager\\"," | "EventName":"EventManager", |
-| test.cs:250:39:250:64 | "\\"EventType\\":\\"Orion\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:250:39:250:64 | "\\"EventType\\":\\"Orion\\"," | "EventType":"Orion", |
-| test.cs:251:4:251:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:251:4:251:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | \\OrionImprovement\\SolarWinds.OrionImprovement.exe |
-| test.cs:252:4:252:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:4:252:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | 0123456789abcdefghijklmnopqrstuvwxyz-_. |
-| test.cs:252:47:252:70 | "\\"sessionId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:47:252:70 | "\\"sessionId\\":\\"{0}\\"," | "sessionId":"{0}", |
-| test.cs:252:73:252:85 | "\\"steps\\":[" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:73:252:85 | "\\"steps\\":[" | "steps":[ |
-| test.cs:253:4:253:24 | "\\"Succeeded\\":true," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:4:253:24 | "\\"Succeeded\\":true," | "Succeeded":true, |
-| test.cs:253:27:253:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:27:253:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | "Timestamp":"\\/Date({0})\\/", |
-| test.cs:253:65:253:85 | "\\"userId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:65:253:85 | "\\"userId\\":\\"{0}\\"," | "userId":"{0}", |
-| test.cs:254:4:254:23 | "{0} {1} HTTP/{2}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:4:254:23 | "{0} {1} HTTP/{2}\n" | {0} {1} HTTP/{2}\n |
-| test.cs:254:26:254:32 | "10140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:26:254:32 | "10140" | 10140 |
-| test.cs:254:35:254:48 | "144.86.226.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:35:254:48 | "144.86.226.0" | 144.86.226.0 |
-| test.cs:254:51:254:65 | "154.118.140.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:51:254:65 | "154.118.140.0" | 154.118.140.0 |
-| test.cs:254:68:254:79 | "172.16.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:68:254:79 | "172.16.0.0" | 172.16.0.0 |
-| test.cs:254:82:254:93 | "18.130.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:82:254:93 | "18.130.0.0" | 18.130.0.0 |
-| test.cs:255:4:255:15 | "184.72.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:4:255:15 | "184.72.0.0" | 184.72.0.0 |
-| test.cs:255:18:255:30 | "192.168.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:18:255:30 | "192.168.0.0" | 192.168.0.0 |
-| test.cs:255:33:255:47 | "199.201.117.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:33:255:47 | "199.201.117.0" | 199.201.117.0 |
-| test.cs:255:50:255:61 | "20.140.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:50:255:61 | "20.140.0.0" | 20.140.0.0 |
-| test.cs:255:64:255:70 | "20100" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:64:255:70 | "20100" | 20100 |
-| test.cs:255:73:255:79 | "20220" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:73:255:79 | "20220" | 20220 |
-| test.cs:255:82:255:94 | "217.163.7.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:82:255:94 | "217.163.7.0" | 217.163.7.0 |
-| test.cs:256:4:256:14 | "224.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:4:256:14 | "224.0.0.0" | 224.0.0.0 |
-| test.cs:256:17:256:27 | "240.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:17:256:27 | "240.0.0.0" | 240.0.0.0 |
-| test.cs:256:30:256:42 | "255.240.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:30:256:42 | "255.240.0.0" | 255.240.0.0 |
-| test.cs:256:45:256:57 | "255.254.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:45:256:57 | "255.254.0.0" | 255.254.0.0 |
-| test.cs:256:60:256:74 | "255.255.248.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:60:256:74 | "255.255.248.0" | 255.255.248.0 |
-| test.cs:256:77:256:87 | "3.0.0.382" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:77:256:87 | "3.0.0.382" | 3.0.0.382 |
-| test.cs:257:4:257:16 | "41.84.159.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:4:257:16 | "41.84.159.0" | 41.84.159.0 |
-| test.cs:257:19:257:25 | "43140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:19:257:25 | "43140" | 43140 |
-| test.cs:257:28:257:33 | "4320" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:28:257:33 | "4320" | 4320 |
-| test.cs:257:36:257:42 | "43260" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:36:257:42 | "43260" | 43260 |
-| test.cs:257:45:257:52 | "524287" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:45:257:52 | "524287" | 524287 |
-| test.cs:257:55:257:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:55:257:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | 583da945-62af-10e8-4902-a8f205c72b2e |
-| test.cs:258:4:258:10 | "65280" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:4:258:10 | "65280" | 65280 |
-| test.cs:258:13:258:25 | "71.152.53.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:13:258:25 | "71.152.53.0" | 71.152.53.0 |
-| test.cs:258:28:258:40 | "74.114.24.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:28:258:40 | "74.114.24.0" | 74.114.24.0 |
-| test.cs:258:43:258:54 | "8.18.144.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:43:258:54 | "8.18.144.0" | 8.18.144.0 |
-| test.cs:258:57:258:69 | "87.238.80.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:57:258:69 | "87.238.80.0" | 87.238.80.0 |
-| test.cs:258:72:258:84 | "96.31.172.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:72:258:84 | "96.31.172.0" | 96.31.172.0 |
-| test.cs:258:87:258:94 | "983040" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:87:258:94 | "983040" | 983040 |
-| test.cs:259:4:259:14 | "99.79.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:4:259:14 | "99.79.0.0" | 99.79.0.0 |
-| test.cs:259:17:259:31 | "Administrator" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:17:259:31 | "Administrator" | Administrator |
-| test.cs:259:34:259:47 | "advapi32.dll" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:34:259:47 | "advapi32.dll" | advapi32.dll |
-| test.cs:259:50:259:57 | "Apollo" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:50:259:57 | "Apollo" | Apollo |
-| test.cs:259:60:259:72 | "appsync-api" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:60:259:72 | "appsync-api" | appsync-api |
-| test.cs:259:75:259:90 | "avsvmcloud.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:75:259:90 | "avsvmcloud.com" | avsvmcloud.com |
-| test.cs:260:4:260:23 | "api.solarwinds.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:4:260:23 | "api.solarwinds.com" | api.solarwinds.com |
-| test.cs:260:26:260:32 | "-root" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:26:260:32 | "-root" | -root |
-| test.cs:260:35:260:41 | "-cert" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:35:260:41 | "-cert" | -cert |
-| test.cs:260:44:260:58 | "-universal_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:44:260:58 | "-universal_ca" | -universal_ca |
-| test.cs:260:61:260:65 | "-ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:61:260:65 | "-ca" | -ca |
-| test.cs:260:68:260:80 | "-primary_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:68:260:80 | "-primary_ca" | -primary_ca |
-| test.cs:260:83:260:94 | "-timestamp" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:83:260:94 | "-timestamp" | -timestamp |
-| test.cs:261:4:261:12 | "-global" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:4:261:12 | "-global" | -global |
-| test.cs:261:15:261:25 | "-secureca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:15:261:25 | "-secureca" | -secureca |
-| test.cs:261:28:261:44 | "CloudMonitoring" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:28:261:44 | "CloudMonitoring" | CloudMonitoring |
-| test.cs:261:47:261:58 | "MACAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:47:261:58 | "MACAddress" | MACAddress |
-| test.cs:261:61:261:73 | "DHCPEnabled" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:61:261:73 | "DHCPEnabled" | DHCPEnabled |
-| test.cs:261:76:261:87 | "DHCPServer" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:76:261:87 | "DHCPServer" | DHCPServer |
-| test.cs:262:4:262:16 | "DNSHostName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:4:262:16 | "DNSHostName" | DNSHostName |
-| test.cs:262:19:262:46 | "DNSDomainSuffixSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:19:262:46 | "DNSDomainSuffixSearchOrder" | DNSDomainSuffixSearchOrder |
-| test.cs:262:49:262:70 | "DNSServerSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:49:262:70 | "DNSServerSearchOrder" | DNSServerSearchOrder |
-| test.cs:262:73:262:83 | "IPAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:73:262:83 | "IPAddress" | IPAddress |
-| test.cs:262:86:262:95 | "IPSubnet" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:86:262:95 | "IPSubnet" | IPSubnet |
-| test.cs:263:4:263:21 | "DefaultIPGateway" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:4:263:21 | "DefaultIPGateway" | DefaultIPGateway |
-| test.cs:263:24:263:39 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:24:263:39 | "OSArchitecture" | OSArchitecture |
-| test.cs:263:42:263:54 | "InstallDate" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:42:263:54 | "InstallDate" | InstallDate |
-| test.cs:263:57:263:70 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:57:263:70 | "Organization" | Organization |
-| test.cs:263:73:263:88 | "RegisteredUser" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:73:263:88 | "RegisteredUser" | RegisteredUser |
-| test.cs:264:4:264:11 | "fc00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:4:264:11 | "fc00::" | fc00:: |
-| test.cs:264:14:264:21 | "fe00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:14:264:21 | "fe00::" | fe00:: |
-| test.cs:264:24:264:31 | "fec0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:24:264:31 | "fec0::" | fec0:: |
-| test.cs:264:34:264:41 | "ffc0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:34:264:41 | "ffc0::" | ffc0:: |
-| test.cs:264:44:264:51 | "ff00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:44:264:51 | "ff00::" | ff00:: |
-| test.cs:264:54:264:59 | "HKCC" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:54:264:59 | "HKCC" | HKCC |
-| test.cs:264:62:264:67 | "HKCR" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:62:264:67 | "HKCR" | HKCR |
-| test.cs:264:70:264:75 | "HKCU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:70:264:75 | "HKCU" | HKCU |
-| test.cs:264:78:264:83 | "HKDD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:78:264:83 | "HKDD" | HKDD |
-| test.cs:265:4:265:22 | "HKEY_CLASSES_ROOT" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:4:265:22 | "HKEY_CLASSES_ROOT" | HKEY_CLASSES_ROOT |
-| test.cs:265:25:265:45 | "HKEY_CURRENT_CONFIG" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:25:265:45 | "HKEY_CURRENT_CONFIG" | HKEY_CURRENT_CONFIG |
-| test.cs:265:48:265:66 | "HKEY_CURRENT_USER" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:48:265:66 | "HKEY_CURRENT_USER" | HKEY_CURRENT_USER |
-| test.cs:265:69:265:83 | "HKEY_DYN_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:69:265:83 | "HKEY_DYN_DATA" | HKEY_DYN_DATA |
-| test.cs:266:4:266:23 | "HKEY_LOCAL_MACHINE" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:4:266:23 | "HKEY_LOCAL_MACHINE" | HKEY_LOCAL_MACHINE |
-| test.cs:266:26:266:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:26:266:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography |
-| test.cs:267:4:267:25 | "HKEY_PERFOMANCE_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:4:267:25 | "HKEY_PERFOMANCE_DATA" | HKEY_PERFOMANCE_DATA |
-| test.cs:267:28:267:39 | "HKEY_USERS" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:28:267:39 | "HKEY_USERS" | HKEY_USERS |
-| test.cs:267:42:267:47 | "HKLM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:42:267:47 | "HKLM" | HKLM |
-| test.cs:267:50:267:55 | "HKPD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:50:267:55 | "HKPD" | HKPD |
-| test.cs:267:58:267:62 | "HKU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:58:267:62 | "HKU" | HKU |
-| test.cs:267:65:267:79 | "If-None-Match" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:65:267:79 | "If-None-Match" | If-None-Match |
-| test.cs:268:4:268:25 | "Microsoft-CryptoAPI/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:4:268:25 | "Microsoft-CryptoAPI/" | Microsoft-CryptoAPI/ |
-| test.cs:268:28:268:34 | "Nodes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:28:268:34 | "Nodes" | Nodes |
-| test.cs:268:37:268:45 | "Volumes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:37:268:45 | "Volumes" | Volumes |
-| test.cs:268:48:268:59 | "Interfaces" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:48:268:59 | "Interfaces" | Interfaces |
-| test.cs:268:62:268:73 | "Components" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:62:268:73 | "Components" | Components |
-| test.cs:268:76:268:85 | "opensans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:76:268:85 | "opensans" | opensans |
-| test.cs:269:4:269:17 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:4:269:17 | "Organization" | Organization |
-| test.cs:269:20:269:35 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:20:269:35 | "OSArchitecture" | OSArchitecture |
-| test.cs:269:38:269:54 | "ParentProcessID" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:38:269:54 | "ParentProcessID" | ParentProcessID |
-| test.cs:269:57:269:66 | "PathName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:57:269:66 | "PathName" | PathName |
-| test.cs:269:69:269:91 | "ReportWatcherPostpone" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:69:269:91 | "ReportWatcherPostpone" | ReportWatcherPostpone |
-| test.cs:270:4:270:23 | "ReportWatcherRetry" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:4:270:23 | "ReportWatcherRetry" | ReportWatcherRetry |
-| test.cs:270:26:270:33 | "S-1-5-" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:26:270:33 | "S-1-5-" | S-1-5- |
-| test.cs:270:36:270:55 | "SeRestorePrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:36:270:55 | "SeRestorePrivilege" | SeRestorePrivilege |
-| test.cs:270:58:270:78 | "SeShutdownPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:58:270:78 | "SeShutdownPrivilege" | SeShutdownPrivilege |
-| test.cs:271:4:271:29 | "SeTakeOwnershipPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:4:271:29 | "SeTakeOwnershipPrivilege" | SeTakeOwnershipPrivilege |
-| test.cs:271:32:271:43 | "SolarWinds" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:32:271:43 | "SolarWinds" | SolarWinds |
-| test.cs:271:46:271:80 | "SolarWindsOrionImprovementClient/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:46:271:80 | "SolarWindsOrionImprovementClient/" | SolarWindsOrionImprovementClient/ |
-| test.cs:272:4:272:18 | "SourceCodePro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:4:272:18 | "SourceCodePro" | SourceCodePro |
-| test.cs:272:21:272:35 | "SourceHanSans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:21:272:35 | "SourceHanSans" | SourceHanSans |
-| test.cs:272:38:272:53 | "SourceHanSerif" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:38:272:53 | "SourceHanSerif" | SourceHanSerif |
-| test.cs:272:56:272:71 | "SourceSerifPro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:56:272:71 | "SourceSerifPro" | SourceSerifPro |
-| test.cs:272:74:272:80 | "Start" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:74:272:80 | "Start" | Start |
-| test.cs:272:83:272:95 | "swip/Events" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:83:272:95 | "swip/Events" | swip/Events |
-| test.cs:273:4:273:14 | "swip/upd/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:4:273:14 | "swip/upd/" | swip/upd/ |
-| test.cs:273:17:273:34 | "swip/Upload.ashx" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:17:273:34 | "swip/Upload.ashx" | swip/Upload.ashx |
-| test.cs:273:37:273:44 | "SYSTEM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:37:273:44 | "SYSTEM" | SYSTEM |
-| test.cs:273:47:273:83 | "SYSTEM\\CurrentControlSet\\services" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:47:273:83 | "SYSTEM\\CurrentControlSet\\services" | SYSTEM\\CurrentControlSet\\services |
-| test.cs:273:86:273:96 | "us-east-1" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:86:273:96 | "us-east-1" | us-east-1 |
-| test.cs:274:4:274:14 | "us-east-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:4:274:14 | "us-east-2" | us-east-2 |
-| test.cs:274:17:274:27 | "us-west-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:17:274:27 | "us-west-2" | us-west-2 |
-| test.cs:274:30:274:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:30:274:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | fonts/woff/{0}-{1}-{2}{3}.woff2 |
-| test.cs:275:4:275:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:4:275:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | fonts/woff/{0}-{1}-{2}-webfont{3}.woff2 |
-| test.cs:275:47:275:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:47:275:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | ph2eifo3n5utg1j8d94qrvbmk0sal76c |
-| test.cs:276:4:276:26 | "pki/crl/{0}{1}{2}.crl" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:276:4:276:26 | "pki/crl/{0}{1}{2}.crl" | pki/crl/{0}{1}{2}.crl |
-| test.cs:276:29:276:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:276:29:276:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | rq3gsalt6u1iyfzop572d49bnx8cvmkewhj |
-| test.cs:277:4:277:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:277:4:277:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true |
-| test.cs:278:4:278:40 | "Select * From Win32_OperatingSystem" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:4:278:40 | "Select * From Win32_OperatingSystem" | Select * From Win32_OperatingSystem |
-| test.cs:278:43:278:71 | "Select * From Win32_Process" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:43:278:71 | "Select * From Win32_Process" | Select * From Win32_Process |
-| test.cs:279:4:279:37 | "Select * From Win32_SystemDriver" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:279:4:279:37 | "Select * From Win32_SystemDriver" | Select * From Win32_SystemDriver |
-| test.cs:279:40:279:72 | "Select * From Win32_UserAccount" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:279:40:279:72 | "Select * From Win32_UserAccount" | Select * From Win32_UserAccount |
+| test.cs:246:4:246:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:246:4:246:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | (?i)([^a-z]\|^)(test)([^a-z]\|$) |
+| test.cs:246:38:246:55 | "(?i)(solarwinds)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:246:38:246:55 | "(?i)(solarwinds)" | (?i)(solarwinds) |
+| test.cs:246:58:246:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:246:58:246:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | [{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n |
+| test.cs:247:4:247:18 | "[{0,5}] {1}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:4:247:18 | "[{0,5}] {1}\n" | [{0,5}] {1}\n |
+| test.cs:247:21:247:37 | "[E] {0} {1} {2}" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:21:247:37 | "[E] {0} {1} {2}" | [E] {0} {1} {2} |
+| test.cs:248:4:248:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:4:248:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | "\\{[0-9a-f-]{36}\\}"\|"[0-9a-f]{32}"\|"[0-9a-f]{16}" |
+| test.cs:248:65:248:79 | ".CortexPlugin" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:65:248:79 | ".CortexPlugin" | .CortexPlugin |
+| test.cs:248:82:248:89 | ".Orion" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:82:248:89 | ".Orion" | .Orion |
+| test.cs:249:4:249:36 | "\\"EventName\\":\\"EventManager\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:4:249:36 | "\\"EventName\\":\\"EventManager\\"," | "EventName":"EventManager", |
+| test.cs:249:39:249:64 | "\\"EventType\\":\\"Orion\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:39:249:64 | "\\"EventType\\":\\"Orion\\"," | "EventType":"Orion", |
+| test.cs:250:4:250:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:250:4:250:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | \\OrionImprovement\\SolarWinds.OrionImprovement.exe |
+| test.cs:251:4:251:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:251:4:251:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | 0123456789abcdefghijklmnopqrstuvwxyz-_. |
+| test.cs:251:47:251:70 | "\\"sessionId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:251:47:251:70 | "\\"sessionId\\":\\"{0}\\"," | "sessionId":"{0}", |
+| test.cs:251:73:251:85 | "\\"steps\\":[" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:251:73:251:85 | "\\"steps\\":[" | "steps":[ |
+| test.cs:252:4:252:24 | "\\"Succeeded\\":true," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:4:252:24 | "\\"Succeeded\\":true," | "Succeeded":true, |
+| test.cs:252:27:252:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:27:252:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | "Timestamp":"\\/Date({0})\\/", |
+| test.cs:252:65:252:85 | "\\"userId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:65:252:85 | "\\"userId\\":\\"{0}\\"," | "userId":"{0}", |
+| test.cs:253:4:253:23 | "{0} {1} HTTP/{2}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:4:253:23 | "{0} {1} HTTP/{2}\n" | {0} {1} HTTP/{2}\n |
+| test.cs:253:26:253:32 | "10140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:26:253:32 | "10140" | 10140 |
+| test.cs:253:35:253:48 | "144.86.226.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:35:253:48 | "144.86.226.0" | 144.86.226.0 |
+| test.cs:253:51:253:65 | "154.118.140.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:51:253:65 | "154.118.140.0" | 154.118.140.0 |
+| test.cs:253:68:253:79 | "172.16.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:68:253:79 | "172.16.0.0" | 172.16.0.0 |
+| test.cs:253:82:253:93 | "18.130.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:82:253:93 | "18.130.0.0" | 18.130.0.0 |
+| test.cs:254:4:254:15 | "184.72.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:4:254:15 | "184.72.0.0" | 184.72.0.0 |
+| test.cs:254:18:254:30 | "192.168.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:18:254:30 | "192.168.0.0" | 192.168.0.0 |
+| test.cs:254:33:254:47 | "199.201.117.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:33:254:47 | "199.201.117.0" | 199.201.117.0 |
+| test.cs:254:50:254:61 | "20.140.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:50:254:61 | "20.140.0.0" | 20.140.0.0 |
+| test.cs:254:64:254:70 | "20100" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:64:254:70 | "20100" | 20100 |
+| test.cs:254:73:254:79 | "20220" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:73:254:79 | "20220" | 20220 |
+| test.cs:254:82:254:94 | "217.163.7.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:82:254:94 | "217.163.7.0" | 217.163.7.0 |
+| test.cs:255:4:255:14 | "224.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:4:255:14 | "224.0.0.0" | 224.0.0.0 |
+| test.cs:255:17:255:27 | "240.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:17:255:27 | "240.0.0.0" | 240.0.0.0 |
+| test.cs:255:30:255:42 | "255.240.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:30:255:42 | "255.240.0.0" | 255.240.0.0 |
+| test.cs:255:45:255:57 | "255.254.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:45:255:57 | "255.254.0.0" | 255.254.0.0 |
+| test.cs:255:60:255:74 | "255.255.248.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:60:255:74 | "255.255.248.0" | 255.255.248.0 |
+| test.cs:255:77:255:87 | "3.0.0.382" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:77:255:87 | "3.0.0.382" | 3.0.0.382 |
+| test.cs:256:4:256:16 | "41.84.159.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:4:256:16 | "41.84.159.0" | 41.84.159.0 |
+| test.cs:256:19:256:25 | "43140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:19:256:25 | "43140" | 43140 |
+| test.cs:256:28:256:33 | "4320" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:28:256:33 | "4320" | 4320 |
+| test.cs:256:36:256:42 | "43260" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:36:256:42 | "43260" | 43260 |
+| test.cs:256:45:256:52 | "524287" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:45:256:52 | "524287" | 524287 |
+| test.cs:256:55:256:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:55:256:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | 583da945-62af-10e8-4902-a8f205c72b2e |
+| test.cs:257:4:257:10 | "65280" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:4:257:10 | "65280" | 65280 |
+| test.cs:257:13:257:25 | "71.152.53.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:13:257:25 | "71.152.53.0" | 71.152.53.0 |
+| test.cs:257:28:257:40 | "74.114.24.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:28:257:40 | "74.114.24.0" | 74.114.24.0 |
+| test.cs:257:43:257:54 | "8.18.144.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:43:257:54 | "8.18.144.0" | 8.18.144.0 |
+| test.cs:257:57:257:69 | "87.238.80.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:57:257:69 | "87.238.80.0" | 87.238.80.0 |
+| test.cs:257:72:257:84 | "96.31.172.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:72:257:84 | "96.31.172.0" | 96.31.172.0 |
+| test.cs:257:87:257:94 | "983040" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:87:257:94 | "983040" | 983040 |
+| test.cs:258:4:258:14 | "99.79.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:4:258:14 | "99.79.0.0" | 99.79.0.0 |
+| test.cs:258:17:258:31 | "Administrator" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:17:258:31 | "Administrator" | Administrator |
+| test.cs:258:34:258:47 | "advapi32.dll" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:34:258:47 | "advapi32.dll" | advapi32.dll |
+| test.cs:258:50:258:57 | "Apollo" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:50:258:57 | "Apollo" | Apollo |
+| test.cs:258:60:258:72 | "appsync-api" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:60:258:72 | "appsync-api" | appsync-api |
+| test.cs:258:75:258:90 | "avsvmcloud.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:75:258:90 | "avsvmcloud.com" | avsvmcloud.com |
+| test.cs:259:4:259:23 | "api.solarwinds.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:4:259:23 | "api.solarwinds.com" | api.solarwinds.com |
+| test.cs:259:26:259:32 | "-root" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:26:259:32 | "-root" | -root |
+| test.cs:259:35:259:41 | "-cert" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:35:259:41 | "-cert" | -cert |
+| test.cs:259:44:259:58 | "-universal_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:44:259:58 | "-universal_ca" | -universal_ca |
+| test.cs:259:61:259:65 | "-ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:61:259:65 | "-ca" | -ca |
+| test.cs:259:68:259:80 | "-primary_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:68:259:80 | "-primary_ca" | -primary_ca |
+| test.cs:259:83:259:94 | "-timestamp" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:83:259:94 | "-timestamp" | -timestamp |
+| test.cs:260:4:260:12 | "-global" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:4:260:12 | "-global" | -global |
+| test.cs:260:15:260:25 | "-secureca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:15:260:25 | "-secureca" | -secureca |
+| test.cs:260:28:260:44 | "CloudMonitoring" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:28:260:44 | "CloudMonitoring" | CloudMonitoring |
+| test.cs:260:47:260:58 | "MACAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:47:260:58 | "MACAddress" | MACAddress |
+| test.cs:260:61:260:73 | "DHCPEnabled" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:61:260:73 | "DHCPEnabled" | DHCPEnabled |
+| test.cs:260:76:260:87 | "DHCPServer" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:76:260:87 | "DHCPServer" | DHCPServer |
+| test.cs:261:4:261:16 | "DNSHostName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:4:261:16 | "DNSHostName" | DNSHostName |
+| test.cs:261:19:261:46 | "DNSDomainSuffixSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:19:261:46 | "DNSDomainSuffixSearchOrder" | DNSDomainSuffixSearchOrder |
+| test.cs:261:49:261:70 | "DNSServerSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:49:261:70 | "DNSServerSearchOrder" | DNSServerSearchOrder |
+| test.cs:261:73:261:83 | "IPAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:73:261:83 | "IPAddress" | IPAddress |
+| test.cs:261:86:261:95 | "IPSubnet" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:86:261:95 | "IPSubnet" | IPSubnet |
+| test.cs:262:4:262:21 | "DefaultIPGateway" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:4:262:21 | "DefaultIPGateway" | DefaultIPGateway |
+| test.cs:262:24:262:39 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:24:262:39 | "OSArchitecture" | OSArchitecture |
+| test.cs:262:42:262:54 | "InstallDate" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:42:262:54 | "InstallDate" | InstallDate |
+| test.cs:262:57:262:70 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:57:262:70 | "Organization" | Organization |
+| test.cs:262:73:262:88 | "RegisteredUser" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:73:262:88 | "RegisteredUser" | RegisteredUser |
+| test.cs:263:4:263:11 | "fc00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:4:263:11 | "fc00::" | fc00:: |
+| test.cs:263:14:263:21 | "fe00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:14:263:21 | "fe00::" | fe00:: |
+| test.cs:263:24:263:31 | "fec0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:24:263:31 | "fec0::" | fec0:: |
+| test.cs:263:34:263:41 | "ffc0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:34:263:41 | "ffc0::" | ffc0:: |
+| test.cs:263:44:263:51 | "ff00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:44:263:51 | "ff00::" | ff00:: |
+| test.cs:263:54:263:59 | "HKCC" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:54:263:59 | "HKCC" | HKCC |
+| test.cs:263:62:263:67 | "HKCR" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:62:263:67 | "HKCR" | HKCR |
+| test.cs:263:70:263:75 | "HKCU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:70:263:75 | "HKCU" | HKCU |
+| test.cs:263:78:263:83 | "HKDD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:78:263:83 | "HKDD" | HKDD |
+| test.cs:264:4:264:22 | "HKEY_CLASSES_ROOT" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:4:264:22 | "HKEY_CLASSES_ROOT" | HKEY_CLASSES_ROOT |
+| test.cs:264:25:264:45 | "HKEY_CURRENT_CONFIG" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:25:264:45 | "HKEY_CURRENT_CONFIG" | HKEY_CURRENT_CONFIG |
+| test.cs:264:48:264:66 | "HKEY_CURRENT_USER" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:48:264:66 | "HKEY_CURRENT_USER" | HKEY_CURRENT_USER |
+| test.cs:264:69:264:83 | "HKEY_DYN_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:69:264:83 | "HKEY_DYN_DATA" | HKEY_DYN_DATA |
+| test.cs:265:4:265:23 | "HKEY_LOCAL_MACHINE" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:4:265:23 | "HKEY_LOCAL_MACHINE" | HKEY_LOCAL_MACHINE |
+| test.cs:265:26:265:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:26:265:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography |
+| test.cs:266:4:266:25 | "HKEY_PERFOMANCE_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:4:266:25 | "HKEY_PERFOMANCE_DATA" | HKEY_PERFOMANCE_DATA |
+| test.cs:266:28:266:39 | "HKEY_USERS" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:28:266:39 | "HKEY_USERS" | HKEY_USERS |
+| test.cs:266:42:266:47 | "HKLM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:42:266:47 | "HKLM" | HKLM |
+| test.cs:266:50:266:55 | "HKPD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:50:266:55 | "HKPD" | HKPD |
+| test.cs:266:58:266:62 | "HKU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:58:266:62 | "HKU" | HKU |
+| test.cs:266:65:266:79 | "If-None-Match" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:65:266:79 | "If-None-Match" | If-None-Match |
+| test.cs:267:4:267:25 | "Microsoft-CryptoAPI/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:4:267:25 | "Microsoft-CryptoAPI/" | Microsoft-CryptoAPI/ |
+| test.cs:267:28:267:34 | "Nodes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:28:267:34 | "Nodes" | Nodes |
+| test.cs:267:37:267:45 | "Volumes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:37:267:45 | "Volumes" | Volumes |
+| test.cs:267:48:267:59 | "Interfaces" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:48:267:59 | "Interfaces" | Interfaces |
+| test.cs:267:62:267:73 | "Components" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:62:267:73 | "Components" | Components |
+| test.cs:267:76:267:85 | "opensans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:76:267:85 | "opensans" | opensans |
+| test.cs:268:4:268:17 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:4:268:17 | "Organization" | Organization |
+| test.cs:268:20:268:35 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:20:268:35 | "OSArchitecture" | OSArchitecture |
+| test.cs:268:38:268:54 | "ParentProcessID" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:38:268:54 | "ParentProcessID" | ParentProcessID |
+| test.cs:268:57:268:66 | "PathName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:57:268:66 | "PathName" | PathName |
+| test.cs:268:69:268:91 | "ReportWatcherPostpone" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:69:268:91 | "ReportWatcherPostpone" | ReportWatcherPostpone |
+| test.cs:269:4:269:23 | "ReportWatcherRetry" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:4:269:23 | "ReportWatcherRetry" | ReportWatcherRetry |
+| test.cs:269:26:269:33 | "S-1-5-" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:26:269:33 | "S-1-5-" | S-1-5- |
+| test.cs:269:36:269:55 | "SeRestorePrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:36:269:55 | "SeRestorePrivilege" | SeRestorePrivilege |
+| test.cs:269:58:269:78 | "SeShutdownPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:58:269:78 | "SeShutdownPrivilege" | SeShutdownPrivilege |
+| test.cs:270:4:270:29 | "SeTakeOwnershipPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:4:270:29 | "SeTakeOwnershipPrivilege" | SeTakeOwnershipPrivilege |
+| test.cs:270:32:270:43 | "SolarWinds" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:32:270:43 | "SolarWinds" | SolarWinds |
+| test.cs:270:46:270:80 | "SolarWindsOrionImprovementClient/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:46:270:80 | "SolarWindsOrionImprovementClient/" | SolarWindsOrionImprovementClient/ |
+| test.cs:271:4:271:18 | "SourceCodePro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:4:271:18 | "SourceCodePro" | SourceCodePro |
+| test.cs:271:21:271:35 | "SourceHanSans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:21:271:35 | "SourceHanSans" | SourceHanSans |
+| test.cs:271:38:271:53 | "SourceHanSerif" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:38:271:53 | "SourceHanSerif" | SourceHanSerif |
+| test.cs:271:56:271:71 | "SourceSerifPro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:56:271:71 | "SourceSerifPro" | SourceSerifPro |
+| test.cs:271:74:271:80 | "Start" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:74:271:80 | "Start" | Start |
+| test.cs:271:83:271:95 | "swip/Events" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:83:271:95 | "swip/Events" | swip/Events |
+| test.cs:272:4:272:14 | "swip/upd/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:4:272:14 | "swip/upd/" | swip/upd/ |
+| test.cs:272:17:272:34 | "swip/Upload.ashx" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:17:272:34 | "swip/Upload.ashx" | swip/Upload.ashx |
+| test.cs:272:37:272:44 | "SYSTEM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:37:272:44 | "SYSTEM" | SYSTEM |
+| test.cs:272:47:272:83 | "SYSTEM\\CurrentControlSet\\services" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:47:272:83 | "SYSTEM\\CurrentControlSet\\services" | SYSTEM\\CurrentControlSet\\services |
+| test.cs:272:86:272:96 | "us-east-1" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:86:272:96 | "us-east-1" | us-east-1 |
+| test.cs:273:4:273:14 | "us-east-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:4:273:14 | "us-east-2" | us-east-2 |
+| test.cs:273:17:273:27 | "us-west-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:17:273:27 | "us-west-2" | us-west-2 |
+| test.cs:273:30:273:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:30:273:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | fonts/woff/{0}-{1}-{2}{3}.woff2 |
+| test.cs:274:4:274:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:4:274:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | fonts/woff/{0}-{1}-{2}-webfont{3}.woff2 |
+| test.cs:274:47:274:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:47:274:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | ph2eifo3n5utg1j8d94qrvbmk0sal76c |
+| test.cs:275:4:275:26 | "pki/crl/{0}{1}{2}.crl" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:4:275:26 | "pki/crl/{0}{1}{2}.crl" | pki/crl/{0}{1}{2}.crl |
+| test.cs:275:29:275:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:29:275:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | rq3gsalt6u1iyfzop572d49bnx8cvmkewhj |
+| test.cs:276:4:276:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:276:4:276:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true |
+| test.cs:277:4:277:40 | "Select * From Win32_OperatingSystem" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:277:4:277:40 | "Select * From Win32_OperatingSystem" | Select * From Win32_OperatingSystem |
+| test.cs:277:43:277:71 | "Select * From Win32_Process" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:277:43:277:71 | "Select * From Win32_Process" | Select * From Win32_Process |
+| test.cs:278:4:278:37 | "Select * From Win32_SystemDriver" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:4:278:37 | "Select * From Win32_SystemDriver" | Select * From Win32_SystemDriver |
+| test.cs:278:40:278:72 | "Select * From Win32_UserAccount" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:40:278:72 | "Select * From Win32_UserAccount" | Select * From Win32_UserAccount |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected
index 625fe686581..8e25d8521be 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected
@@ -1,104 +1,104 @@
-| test.cs:66:7:66:11 | Abort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:66:7:66:11 | Abort | Abort |
-| test.cs:67:7:67:28 | AddFileExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:67:7:67:28 | AddFileExecutionEngine | AddFileExecutionEngine |
-| test.cs:68:7:68:32 | AddRegistryExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:68:7:68:32 | AddRegistryExecutionEngine | AddRegistryExecutionEngine |
-| test.cs:69:7:69:27 | AdjustTokenPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:69:7:69:27 | AdjustTokenPrivileges | AdjustTokenPrivileges |
-| test.cs:70:7:70:18 | Base64Decode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:70:7:70:18 | Base64Decode | Base64Decode |
-| test.cs:71:7:71:18 | Base64Encode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:71:7:71:18 | Base64Encode | Base64Encode |
-| test.cs:72:7:72:26 | ByteArrayToHexString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:72:7:72:26 | ByteArrayToHexString | ByteArrayToHexString |
-| test.cs:73:7:73:27 | CheckServerConnection | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:73:7:73:27 | CheckServerConnection | CheckServerConnection |
-| test.cs:74:7:74:11 | Close | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:74:7:74:11 | Close | Close |
-| test.cs:75:7:75:17 | CloseHandle | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:75:7:75:17 | CloseHandle | CloseHandle |
-| test.cs:76:7:76:30 | CollectSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:76:7:76:30 | CollectSystemDescription | CollectSystemDescription |
-| test.cs:77:7:77:14 | Compress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:77:7:77:14 | Compress | Compress |
-| test.cs:78:7:78:24 | CreateSecureString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:78:7:78:24 | CreateSecureString | CreateSecureString |
-| test.cs:79:7:79:18 | CreateString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:79:7:79:18 | CreateString | CreateString |
-| test.cs:80:7:80:25 | CreateUploadRequest | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:80:7:80:25 | CreateUploadRequest | CreateUploadRequest |
-| test.cs:81:7:81:29 | CreateUploadRequestImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:81:7:81:29 | CreateUploadRequestImpl | CreateUploadRequestImpl |
-| test.cs:82:7:82:16 | Decompress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:82:7:82:16 | Decompress | Decompress |
-| test.cs:83:7:83:18 | DecryptShort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:83:7:83:18 | DecryptShort | DecryptShort |
-| test.cs:84:7:84:13 | Deflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:84:7:84:13 | Deflate | Deflate |
-| test.cs:85:7:85:14 | DelayMin | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:85:7:85:14 | DelayMin | DelayMin |
-| test.cs:86:7:86:13 | DelayMs | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:86:7:86:13 | DelayMs | DelayMs |
-| test.cs:87:7:87:16 | DeleteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:87:7:87:16 | DeleteFile | DeleteFile |
-| test.cs:88:7:88:25 | DeleteRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:88:7:88:25 | DeleteRegistryValue | DeleteRegistryValue |
-| test.cs:89:7:89:17 | DeleteValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:89:7:89:17 | DeleteValue | DeleteValue |
-| test.cs:90:7:90:19 | ExecuteEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:90:7:90:19 | ExecuteEngine | ExecuteEngine |
-| test.cs:91:7:91:16 | FileExists | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:91:7:91:16 | FileExists | FileExists |
-| test.cs:92:7:92:18 | GetAddresses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:92:7:92:18 | GetAddresses | GetAddresses |
-| test.cs:93:7:93:22 | GetAddressFamily | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:93:7:93:22 | GetAddressFamily | GetAddressFamily |
-| test.cs:94:7:94:22 | GetArgumentIndex | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:94:7:94:22 | GetArgumentIndex | GetArgumentIndex |
-| test.cs:95:7:95:16 | GetBaseUri | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:95:7:95:16 | GetBaseUri | GetBaseUri |
-| test.cs:96:7:96:20 | GetBaseUriImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:96:7:96:20 | GetBaseUriImpl | GetBaseUriImpl |
-| test.cs:97:7:97:14 | GetCache | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:97:7:97:14 | GetCache | GetCache |
-| test.cs:98:7:98:23 | GetCurrentProcess | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:98:7:98:23 | GetCurrentProcess | GetCurrentProcess |
-| test.cs:99:7:99:22 | GetCurrentString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:99:7:99:22 | GetCurrentString | GetCurrentString |
-| test.cs:100:7:100:22 | GetDescriptionId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:100:7:100:22 | GetDescriptionId | GetDescriptionId |
-| test.cs:101:7:101:17 | GetFileHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:101:7:101:17 | GetFileHash | GetFileHash |
-| test.cs:102:7:102:26 | GetFileSystemEntries | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:102:7:102:26 | GetFileSystemEntries | GetFileSystemEntries |
-| test.cs:103:7:103:13 | GetHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:103:7:103:13 | GetHash | GetHash |
-| test.cs:104:7:104:13 | GetHive | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:104:7:104:13 | GetHive | GetHive |
-| test.cs:105:7:105:17 | GetIntArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:105:7:105:17 | GetIntArray | GetIntArray |
-| test.cs:106:7:106:20 | GetIPHostEntry | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:106:7:106:20 | GetIPHostEntry | GetIPHostEntry |
-| test.cs:107:7:107:33 | GetManagementObjectProperty | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:107:7:107:33 | GetManagementObjectProperty | GetManagementObjectProperty |
-| test.cs:108:7:108:36 | GetNetworkAdapterConfiguration | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:108:7:108:36 | GetNetworkAdapterConfiguration | GetNetworkAdapterConfiguration |
-| test.cs:109:7:109:21 | GetNewOwnerName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:109:7:109:21 | GetNewOwnerName | GetNewOwnerName |
-| test.cs:110:7:110:19 | GetNextString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:110:7:110:19 | GetNextString | GetNextString |
-| test.cs:111:7:111:21 | GetNextStringEx | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:111:7:111:21 | GetNextStringEx | GetNextStringEx |
-| test.cs:112:7:112:23 | GetOrCreateUserID | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:112:7:112:23 | GetOrCreateUserID | GetOrCreateUserID |
-| test.cs:113:7:113:35 | GetOrionImprovementCustomerId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:113:7:113:35 | GetOrionImprovementCustomerId | GetOrionImprovementCustomerId |
-| test.cs:114:7:114:18 | GetOSVersion | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:114:7:114:18 | GetOSVersion | GetOSVersion |
-| test.cs:115:7:115:23 | GetPreviousString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:115:7:115:23 | GetPreviousString | GetPreviousString |
-| test.cs:116:7:116:29 | GetProcessByDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:116:7:116:29 | GetProcessByDescription | GetProcessByDescription |
-| test.cs:117:7:117:36 | GetRegistrySubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:117:7:117:36 | GetRegistrySubKeyAndValueNames | GetRegistrySubKeyAndValueNames |
-| test.cs:118:7:118:15 | GetStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:118:7:118:15 | GetStatus | GetStatus |
-| test.cs:119:7:119:19 | GetStringHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:119:7:119:19 | GetStringHash | GetStringHash |
-| test.cs:120:7:120:28 | GetSubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:120:7:120:28 | GetSubKeyAndValueNames | GetSubKeyAndValueNames |
-| test.cs:121:7:121:18 | GetUserAgent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:121:7:121:18 | GetUserAgent | GetUserAgent |
-| test.cs:122:7:122:14 | GetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:122:7:122:14 | GetValue | GetValue |
-| test.cs:123:7:123:17 | GetWebProxy | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:123:7:123:17 | GetWebProxy | GetWebProxy |
-| test.cs:124:7:124:26 | HexStringToByteArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:124:7:124:26 | HexStringToByteArray | HexStringToByteArray |
-| test.cs:125:7:125:13 | Inflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:125:7:125:13 | Inflate | Inflate |
-| test.cs:126:7:126:16 | Initialize | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:126:7:126:16 | Initialize | Initialize |
-| test.cs:127:7:127:31 | InitiateSystemShutdownExW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:127:7:127:31 | InitiateSystemShutdownExW | InitiateSystemShutdownExW |
-| test.cs:128:7:128:25 | IsNullOrInvalidName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:128:7:128:25 | IsNullOrInvalidName | IsNullOrInvalidName |
-| test.cs:129:7:129:20 | IsSynchronized | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:129:7:129:20 | IsSynchronized | IsSynchronized |
-| test.cs:130:7:130:14 | KillTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:130:7:130:14 | KillTask | KillTask |
-| test.cs:131:7:131:27 | LookupPrivilegeValueW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:131:7:131:27 | LookupPrivilegeValueW | LookupPrivilegeValueW |
-| test.cs:132:7:132:22 | OpenProcessToken | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:132:7:132:22 | OpenProcessToken | OpenProcessToken |
-| test.cs:133:7:133:26 | ParseServiceResponse | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:133:7:133:26 | ParseServiceResponse | ParseServiceResponse |
-| test.cs:134:7:134:11 | Quote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:134:7:134:11 | Quote | Quote |
-| test.cs:135:7:135:16 | ReadConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:135:7:135:16 | ReadConfig | ReadConfig |
-| test.cs:136:7:136:20 | ReadDeviceInfo | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:136:7:136:20 | ReadDeviceInfo | ReadDeviceInfo |
-| test.cs:137:7:137:23 | ReadRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:137:7:137:23 | ReadRegistryValue | ReadRegistryValue |
-| test.cs:138:7:138:22 | ReadReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:138:7:138:22 | ReadReportStatus | ReadReportStatus |
-| test.cs:139:7:139:23 | ReadServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:139:7:139:23 | ReadServiceStatus | ReadServiceStatus |
-| test.cs:140:7:140:20 | RebootComputer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:140:7:140:20 | RebootComputer | RebootComputer |
-| test.cs:141:7:141:13 | RunTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:141:7:141:13 | RunTask | RunTask |
-| test.cs:142:7:142:22 | SearchAssemblies | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:142:7:142:22 | SearchAssemblies | SearchAssemblies |
-| test.cs:143:7:143:26 | SearchConfigurations | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:143:7:143:26 | SearchConfigurations | SearchConfigurations |
-| test.cs:144:7:144:20 | SearchServices | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:144:7:144:20 | SearchServices | SearchServices |
-| test.cs:145:7:145:22 | SetAutomaticMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:145:7:145:22 | SetAutomaticMode | SetAutomaticMode |
-| test.cs:146:7:146:17 | SetKeyOwner | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:146:7:146:17 | SetKeyOwner | SetKeyOwner |
-| test.cs:147:7:147:31 | SetKeyOwnerWithPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:147:7:147:31 | SetKeyOwnerWithPrivileges | SetKeyOwnerWithPrivileges |
-| test.cs:148:7:148:23 | SetKeyPermissions | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:148:7:148:23 | SetKeyPermissions | SetKeyPermissions |
-| test.cs:149:7:149:19 | SetManualMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:149:7:149:19 | SetManualMode | SetManualMode |
-| test.cs:150:7:150:25 | SetProcessPrivilege | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:150:7:150:25 | SetProcessPrivilege | SetProcessPrivilege |
-| test.cs:151:7:151:22 | SetRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:151:7:151:22 | SetRegistryValue | SetRegistryValue |
-| test.cs:152:7:152:13 | SetTime | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:152:7:152:13 | SetTime | SetTime |
-| test.cs:153:7:153:14 | SetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:153:7:153:14 | SetValue | SetValue |
-| test.cs:154:7:154:17 | SplitString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:154:7:154:17 | SplitString | SplitString |
-| test.cs:155:7:155:14 | ToString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:155:7:155:14 | ToString | ToString |
-| test.cs:156:7:156:16 | TrackEvent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:156:7:156:16 | TrackEvent | TrackEvent |
-| test.cs:157:7:157:20 | TrackProcesses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:157:7:157:20 | TrackProcesses | TrackProcesses |
-| test.cs:158:7:158:13 | Unquote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:158:7:158:13 | Unquote | Unquote |
-| test.cs:159:7:159:11 | Unzip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:159:7:159:11 | Unzip | Unzip |
-| test.cs:160:7:160:12 | Update | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:160:7:160:12 | Update | Update |
-| test.cs:161:7:161:18 | UpdateBuffer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:161:7:161:18 | UpdateBuffer | UpdateBuffer |
-| test.cs:162:7:162:24 | UpdateNotification | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:162:7:162:24 | UpdateNotification | UpdateNotification |
-| test.cs:163:7:163:29 | UploadSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:163:7:163:29 | UploadSystemDescription | UploadSystemDescription |
-| test.cs:164:7:164:11 | Valid | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:164:7:164:11 | Valid | Valid |
-| test.cs:165:7:165:17 | WriteConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:165:7:165:17 | WriteConfig | WriteConfig |
-| test.cs:166:7:166:15 | WriteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:166:7:166:15 | WriteFile | WriteFile |
-| test.cs:167:7:167:23 | WriteReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:167:7:167:23 | WriteReportStatus | WriteReportStatus |
-| test.cs:168:7:168:24 | WriteServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:168:7:168:24 | WriteServiceStatus | WriteServiceStatus |
-| test.cs:169:7:169:9 | Zip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:169:7:169:9 | Zip | Zip |
+| test.cs:65:7:65:11 | Abort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:65:7:65:11 | Abort | Abort |
+| test.cs:66:7:66:28 | AddFileExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:66:7:66:28 | AddFileExecutionEngine | AddFileExecutionEngine |
+| test.cs:67:7:67:32 | AddRegistryExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:67:7:67:32 | AddRegistryExecutionEngine | AddRegistryExecutionEngine |
+| test.cs:68:7:68:27 | AdjustTokenPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:68:7:68:27 | AdjustTokenPrivileges | AdjustTokenPrivileges |
+| test.cs:69:7:69:18 | Base64Decode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:69:7:69:18 | Base64Decode | Base64Decode |
+| test.cs:70:7:70:18 | Base64Encode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:70:7:70:18 | Base64Encode | Base64Encode |
+| test.cs:71:7:71:26 | ByteArrayToHexString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:71:7:71:26 | ByteArrayToHexString | ByteArrayToHexString |
+| test.cs:72:7:72:27 | CheckServerConnection | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:72:7:72:27 | CheckServerConnection | CheckServerConnection |
+| test.cs:73:7:73:11 | Close | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:73:7:73:11 | Close | Close |
+| test.cs:74:7:74:17 | CloseHandle | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:74:7:74:17 | CloseHandle | CloseHandle |
+| test.cs:75:7:75:30 | CollectSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:75:7:75:30 | CollectSystemDescription | CollectSystemDescription |
+| test.cs:76:7:76:14 | Compress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:76:7:76:14 | Compress | Compress |
+| test.cs:77:7:77:24 | CreateSecureString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:77:7:77:24 | CreateSecureString | CreateSecureString |
+| test.cs:78:7:78:18 | CreateString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:78:7:78:18 | CreateString | CreateString |
+| test.cs:79:7:79:25 | CreateUploadRequest | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:79:7:79:25 | CreateUploadRequest | CreateUploadRequest |
+| test.cs:80:7:80:29 | CreateUploadRequestImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:80:7:80:29 | CreateUploadRequestImpl | CreateUploadRequestImpl |
+| test.cs:81:7:81:16 | Decompress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:81:7:81:16 | Decompress | Decompress |
+| test.cs:82:7:82:18 | DecryptShort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:82:7:82:18 | DecryptShort | DecryptShort |
+| test.cs:83:7:83:13 | Deflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:83:7:83:13 | Deflate | Deflate |
+| test.cs:84:7:84:14 | DelayMin | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:84:7:84:14 | DelayMin | DelayMin |
+| test.cs:85:7:85:13 | DelayMs | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:85:7:85:13 | DelayMs | DelayMs |
+| test.cs:86:7:86:16 | DeleteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:86:7:86:16 | DeleteFile | DeleteFile |
+| test.cs:87:7:87:25 | DeleteRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:87:7:87:25 | DeleteRegistryValue | DeleteRegistryValue |
+| test.cs:88:7:88:17 | DeleteValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:88:7:88:17 | DeleteValue | DeleteValue |
+| test.cs:89:7:89:19 | ExecuteEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:89:7:89:19 | ExecuteEngine | ExecuteEngine |
+| test.cs:90:7:90:16 | FileExists | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:90:7:90:16 | FileExists | FileExists |
+| test.cs:91:7:91:18 | GetAddresses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:91:7:91:18 | GetAddresses | GetAddresses |
+| test.cs:92:7:92:22 | GetAddressFamily | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:92:7:92:22 | GetAddressFamily | GetAddressFamily |
+| test.cs:93:7:93:22 | GetArgumentIndex | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:93:7:93:22 | GetArgumentIndex | GetArgumentIndex |
+| test.cs:94:7:94:16 | GetBaseUri | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:94:7:94:16 | GetBaseUri | GetBaseUri |
+| test.cs:95:7:95:20 | GetBaseUriImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:95:7:95:20 | GetBaseUriImpl | GetBaseUriImpl |
+| test.cs:96:7:96:14 | GetCache | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:96:7:96:14 | GetCache | GetCache |
+| test.cs:97:7:97:23 | GetCurrentProcess | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:97:7:97:23 | GetCurrentProcess | GetCurrentProcess |
+| test.cs:98:7:98:22 | GetCurrentString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:98:7:98:22 | GetCurrentString | GetCurrentString |
+| test.cs:99:7:99:22 | GetDescriptionId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:99:7:99:22 | GetDescriptionId | GetDescriptionId |
+| test.cs:100:7:100:17 | GetFileHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:100:7:100:17 | GetFileHash | GetFileHash |
+| test.cs:101:7:101:26 | GetFileSystemEntries | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:101:7:101:26 | GetFileSystemEntries | GetFileSystemEntries |
+| test.cs:102:7:102:13 | GetHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:102:7:102:13 | GetHash | GetHash |
+| test.cs:103:7:103:13 | GetHive | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:103:7:103:13 | GetHive | GetHive |
+| test.cs:104:7:104:17 | GetIntArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:104:7:104:17 | GetIntArray | GetIntArray |
+| test.cs:105:7:105:20 | GetIPHostEntry | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:105:7:105:20 | GetIPHostEntry | GetIPHostEntry |
+| test.cs:106:7:106:33 | GetManagementObjectProperty | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:106:7:106:33 | GetManagementObjectProperty | GetManagementObjectProperty |
+| test.cs:107:7:107:36 | GetNetworkAdapterConfiguration | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:107:7:107:36 | GetNetworkAdapterConfiguration | GetNetworkAdapterConfiguration |
+| test.cs:108:7:108:21 | GetNewOwnerName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:108:7:108:21 | GetNewOwnerName | GetNewOwnerName |
+| test.cs:109:7:109:19 | GetNextString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:109:7:109:19 | GetNextString | GetNextString |
+| test.cs:110:7:110:21 | GetNextStringEx | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:110:7:110:21 | GetNextStringEx | GetNextStringEx |
+| test.cs:111:7:111:23 | GetOrCreateUserID | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:111:7:111:23 | GetOrCreateUserID | GetOrCreateUserID |
+| test.cs:112:7:112:35 | GetOrionImprovementCustomerId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:112:7:112:35 | GetOrionImprovementCustomerId | GetOrionImprovementCustomerId |
+| test.cs:113:7:113:18 | GetOSVersion | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:113:7:113:18 | GetOSVersion | GetOSVersion |
+| test.cs:114:7:114:23 | GetPreviousString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:114:7:114:23 | GetPreviousString | GetPreviousString |
+| test.cs:115:7:115:29 | GetProcessByDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:115:7:115:29 | GetProcessByDescription | GetProcessByDescription |
+| test.cs:116:7:116:36 | GetRegistrySubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:116:7:116:36 | GetRegistrySubKeyAndValueNames | GetRegistrySubKeyAndValueNames |
+| test.cs:117:7:117:15 | GetStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:117:7:117:15 | GetStatus | GetStatus |
+| test.cs:118:7:118:19 | GetStringHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:118:7:118:19 | GetStringHash | GetStringHash |
+| test.cs:119:7:119:28 | GetSubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:119:7:119:28 | GetSubKeyAndValueNames | GetSubKeyAndValueNames |
+| test.cs:120:7:120:18 | GetUserAgent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:120:7:120:18 | GetUserAgent | GetUserAgent |
+| test.cs:121:7:121:14 | GetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:121:7:121:14 | GetValue | GetValue |
+| test.cs:122:7:122:17 | GetWebProxy | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:122:7:122:17 | GetWebProxy | GetWebProxy |
+| test.cs:123:7:123:26 | HexStringToByteArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:123:7:123:26 | HexStringToByteArray | HexStringToByteArray |
+| test.cs:124:7:124:13 | Inflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:124:7:124:13 | Inflate | Inflate |
+| test.cs:125:7:125:16 | Initialize | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:125:7:125:16 | Initialize | Initialize |
+| test.cs:126:7:126:31 | InitiateSystemShutdownExW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:126:7:126:31 | InitiateSystemShutdownExW | InitiateSystemShutdownExW |
+| test.cs:127:7:127:25 | IsNullOrInvalidName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:127:7:127:25 | IsNullOrInvalidName | IsNullOrInvalidName |
+| test.cs:128:7:128:20 | IsSynchronized | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:128:7:128:20 | IsSynchronized | IsSynchronized |
+| test.cs:129:7:129:14 | KillTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:129:7:129:14 | KillTask | KillTask |
+| test.cs:130:7:130:27 | LookupPrivilegeValueW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:130:7:130:27 | LookupPrivilegeValueW | LookupPrivilegeValueW |
+| test.cs:131:7:131:22 | OpenProcessToken | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:131:7:131:22 | OpenProcessToken | OpenProcessToken |
+| test.cs:132:7:132:26 | ParseServiceResponse | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:132:7:132:26 | ParseServiceResponse | ParseServiceResponse |
+| test.cs:133:7:133:11 | Quote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:133:7:133:11 | Quote | Quote |
+| test.cs:134:7:134:16 | ReadConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:134:7:134:16 | ReadConfig | ReadConfig |
+| test.cs:135:7:135:20 | ReadDeviceInfo | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:135:7:135:20 | ReadDeviceInfo | ReadDeviceInfo |
+| test.cs:136:7:136:23 | ReadRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:136:7:136:23 | ReadRegistryValue | ReadRegistryValue |
+| test.cs:137:7:137:22 | ReadReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:137:7:137:22 | ReadReportStatus | ReadReportStatus |
+| test.cs:138:7:138:23 | ReadServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:138:7:138:23 | ReadServiceStatus | ReadServiceStatus |
+| test.cs:139:7:139:20 | RebootComputer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:139:7:139:20 | RebootComputer | RebootComputer |
+| test.cs:140:7:140:13 | RunTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:140:7:140:13 | RunTask | RunTask |
+| test.cs:141:7:141:22 | SearchAssemblies | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:141:7:141:22 | SearchAssemblies | SearchAssemblies |
+| test.cs:142:7:142:26 | SearchConfigurations | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:142:7:142:26 | SearchConfigurations | SearchConfigurations |
+| test.cs:143:7:143:20 | SearchServices | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:143:7:143:20 | SearchServices | SearchServices |
+| test.cs:144:7:144:22 | SetAutomaticMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:144:7:144:22 | SetAutomaticMode | SetAutomaticMode |
+| test.cs:145:7:145:17 | SetKeyOwner | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:145:7:145:17 | SetKeyOwner | SetKeyOwner |
+| test.cs:146:7:146:31 | SetKeyOwnerWithPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:146:7:146:31 | SetKeyOwnerWithPrivileges | SetKeyOwnerWithPrivileges |
+| test.cs:147:7:147:23 | SetKeyPermissions | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:147:7:147:23 | SetKeyPermissions | SetKeyPermissions |
+| test.cs:148:7:148:19 | SetManualMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:148:7:148:19 | SetManualMode | SetManualMode |
+| test.cs:149:7:149:25 | SetProcessPrivilege | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:149:7:149:25 | SetProcessPrivilege | SetProcessPrivilege |
+| test.cs:150:7:150:22 | SetRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:150:7:150:22 | SetRegistryValue | SetRegistryValue |
+| test.cs:151:7:151:13 | SetTime | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:151:7:151:13 | SetTime | SetTime |
+| test.cs:152:7:152:14 | SetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:152:7:152:14 | SetValue | SetValue |
+| test.cs:153:7:153:17 | SplitString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:153:7:153:17 | SplitString | SplitString |
+| test.cs:154:7:154:14 | ToString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:154:7:154:14 | ToString | ToString |
+| test.cs:155:7:155:16 | TrackEvent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:155:7:155:16 | TrackEvent | TrackEvent |
+| test.cs:156:7:156:20 | TrackProcesses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:156:7:156:20 | TrackProcesses | TrackProcesses |
+| test.cs:157:7:157:13 | Unquote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:157:7:157:13 | Unquote | Unquote |
+| test.cs:158:7:158:11 | Unzip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:158:7:158:11 | Unzip | Unzip |
+| test.cs:159:7:159:12 | Update | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:159:7:159:12 | Update | Update |
+| test.cs:160:7:160:18 | UpdateBuffer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:160:7:160:18 | UpdateBuffer | UpdateBuffer |
+| test.cs:161:7:161:24 | UpdateNotification | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:161:7:161:24 | UpdateNotification | UpdateNotification |
+| test.cs:162:7:162:29 | UploadSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:162:7:162:29 | UploadSystemDescription | UploadSystemDescription |
+| test.cs:163:7:163:11 | Valid | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:163:7:163:11 | Valid | Valid |
+| test.cs:164:7:164:17 | WriteConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:164:7:164:17 | WriteConfig | WriteConfig |
+| test.cs:165:7:165:15 | WriteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:165:7:165:15 | WriteFile | WriteFile |
+| test.cs:166:7:166:23 | WriteReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:166:7:166:23 | WriteReportStatus | WriteReportStatus |
+| test.cs:167:7:167:24 | WriteServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:167:7:167:24 | WriteServiceStatus | WriteServiceStatus |
+| test.cs:168:7:168:9 | Zip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:168:7:168:9 | Zip | Zip |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected
index 9125049047e..0c512115365 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected
@@ -1,3 +1,3 @@
-| test.cs:35:3:38:3 | catch {...} | Empty Swallow Everything Exception. |
-| test.cs:289:3:290:4 | catch {...} | Empty Swallow Everything Exception. |
-| test.cs:295:3:298:3 | catch (...) {...} | Empty Swallow Everything Exception. |
+| test.cs:34:3:37:3 | catch {...} | Empty Swallow Everything Exception. |
+| test.cs:288:3:289:4 | catch {...} | Empty Swallow Everything Exception. |
+| test.cs:294:3:297:3 | catch (...) {...} | Empty Swallow Everything Exception. |
diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs
index 1ee9403a5f1..8680d834694 100644
--- a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs
+++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs
@@ -1,7 +1,6 @@
using System;
using System.Text;
-
class FalsePositiveCases
{
// regular FVN
diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
index 61ffd2f8266..1d53475b58c 100644
--- a/csharp/ql/test/experimental/ir/ir/PrintAst.expected
+++ b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
@@ -1168,139 +1168,139 @@ stmts.cs:
# 40| 0: [LocalVariableAccess] access to local variable select
# 42| 3: [ReturnStmt] return ...;
# 42| 0: [IntLiteral] 0
-# 46| 8: [Method] tryCatchFinally
-# 46| -1: [TypeMention] Void
-# 47| 4: [BlockStmt] {...}
-# 48| 0: [LocalVariableDeclStmt] ... ...;
-# 48| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
-# 48| -1: [TypeMention] int
-# 48| 0: [LocalVariableAccess] access to local variable x
-# 48| 1: [IntLiteral] 5
-# 49| 1: [TryStmt] try {...} ...
-# 64| -1: [BlockStmt] {...}
-# 65| 0: [ExprStmt] ...;
-# 65| 0: [AssignExpr] ... = ...
-# 65| 0: [LocalVariableAccess] access to local variable x
-# 65| 1: [IntLiteral] 2
-# 50| 0: [BlockStmt] {...}
-# 51| 0: [IfStmt] if (...) ...
-# 51| 0: [NEExpr] ... != ...
-# 51| 0: [LocalVariableAccess] access to local variable x
-# 51| 1: [IntLiteral] 0
-# 52| 1: [ThrowStmt] throw ...;
-# 52| 0: [ObjectCreation] object creation of type Exception
-# 52| 0: [TypeMention] Exception
-# 53| 1: [ExprStmt] ...;
-# 53| 0: [AssignExpr] ... = ...
-# 53| 0: [LocalVariableAccess] access to local variable x
-# 53| 1: [IntLiteral] 0
-# 55| 1: [SpecificCatchClause] catch (...) {...}
-# 55| 0: [LocalVariableDeclExpr] Exception ex
-# 55| 0: [TypeMention] Exception
-# 56| 1: [BlockStmt] {...}
-# 57| 0: [ExprStmt] ...;
-# 57| 0: [AssignExpr] ... = ...
-# 57| 0: [LocalVariableAccess] access to local variable x
-# 57| 1: [IntLiteral] 1
-# 59| 2: [GeneralCatchClause] catch {...}
-# 60| 1: [BlockStmt] {...}
-# 61| 0: [ThrowStmt] throw ...;
-# 69| 9: [Method] forStmt
-# 69| -1: [TypeMention] Void
-# 70| 4: [BlockStmt] {...}
-# 71| 0: [LocalVariableDeclStmt] ... ...;
-# 71| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 45| 8: [Method] tryCatchFinally
+# 45| -1: [TypeMention] Void
+# 46| 4: [BlockStmt] {...}
+# 47| 0: [LocalVariableDeclStmt] ... ...;
+# 47| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 47| -1: [TypeMention] int
+# 47| 0: [LocalVariableAccess] access to local variable x
+# 47| 1: [IntLiteral] 5
+# 48| 1: [TryStmt] try {...} ...
+# 63| -1: [BlockStmt] {...}
+# 64| 0: [ExprStmt] ...;
+# 64| 0: [AssignExpr] ... = ...
+# 64| 0: [LocalVariableAccess] access to local variable x
+# 64| 1: [IntLiteral] 2
+# 49| 0: [BlockStmt] {...}
+# 50| 0: [IfStmt] if (...) ...
+# 50| 0: [NEExpr] ... != ...
+# 50| 0: [LocalVariableAccess] access to local variable x
+# 50| 1: [IntLiteral] 0
+# 51| 1: [ThrowStmt] throw ...;
+# 51| 0: [ObjectCreation] object creation of type Exception
+# 51| 0: [TypeMention] Exception
+# 52| 1: [ExprStmt] ...;
+# 52| 0: [AssignExpr] ... = ...
+# 52| 0: [LocalVariableAccess] access to local variable x
+# 52| 1: [IntLiteral] 0
+# 54| 1: [SpecificCatchClause] catch (...) {...}
+# 54| 0: [LocalVariableDeclExpr] Exception ex
+# 54| 0: [TypeMention] Exception
+# 55| 1: [BlockStmt] {...}
+# 56| 0: [ExprStmt] ...;
+# 56| 0: [AssignExpr] ... = ...
+# 56| 0: [LocalVariableAccess] access to local variable x
+# 56| 1: [IntLiteral] 1
+# 58| 2: [GeneralCatchClause] catch {...}
+# 59| 1: [BlockStmt] {...}
+# 60| 0: [ThrowStmt] throw ...;
+# 68| 9: [Method] forStmt
+# 68| -1: [TypeMention] Void
+# 69| 4: [BlockStmt] {...}
+# 70| 0: [LocalVariableDeclStmt] ... ...;
+# 70| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 70| -1: [TypeMention] int
+# 70| 0: [LocalVariableAccess] access to local variable x
+# 70| 1: [IntLiteral] 0
+# 71| 1: [ForStmt] for (...;...;...) ...
+# 71| -2: [LocalVariableDeclAndInitExpr] Int32 j = ...
# 71| -1: [TypeMention] int
-# 71| 0: [LocalVariableAccess] access to local variable x
+# 71| 0: [LocalVariableAccess] access to local variable j
+# 71| 1: [IntLiteral] 10
+# 71| -1: [LocalVariableDeclAndInitExpr] Int32 i = ...
+# 71| -1: [TypeMention] int
+# 71| 0: [LocalVariableAccess] access to local variable i
# 71| 1: [IntLiteral] 0
-# 72| 1: [ForStmt] for (...;...;...) ...
-# 72| -2: [LocalVariableDeclAndInitExpr] Int32 j = ...
-# 72| -1: [TypeMention] int
-# 72| 0: [LocalVariableAccess] access to local variable j
-# 72| 1: [IntLiteral] 10
-# 72| -1: [LocalVariableDeclAndInitExpr] Int32 i = ...
-# 72| -1: [TypeMention] int
-# 72| 0: [LocalVariableAccess] access to local variable i
-# 72| 1: [IntLiteral] 0
-# 72| 0: [LTExpr] ... < ...
-# 72| 0: [LocalVariableAccess] access to local variable i
-# 72| 1: [LocalVariableAccess] access to local variable j
-# 72| 1: [PostIncrExpr] ...++
-# 72| 0: [LocalVariableAccess] access to local variable i
-# 72| 2: [PostDecrExpr] ...--
-# 72| 0: [LocalVariableAccess] access to local variable j
-# 73| 3: [BlockStmt] {...}
-# 74| 0: [ExprStmt] ...;
-# 74| 0: [AssignExpr] ... = ...
-# 74| 0: [LocalVariableAccess] access to local variable x
-# 74| 1: [SubExpr] ... - ...
-# 74| 0: [LocalVariableAccess] access to local variable x
-# 74| 1: [IntLiteral] 1
-# 77| 2: [LocalVariableDeclStmt] ... ...;
-# 77| 0: [LocalVariableDeclExpr] Int32 a
-# 77| 0: [TypeMention] int
-# 77| 1: [LocalVariableDeclAndInitExpr] Int32 b = ...
-# 77| -1: [TypeMention] int
-# 77| 0: [LocalVariableAccess] access to local variable b
-# 77| 1: [IntLiteral] 10
-# 78| 3: [ForStmt] for (...;...;...) ...
-# 78| -1: [AssignExpr] ... = ...
-# 78| 0: [LocalVariableAccess] access to local variable a
-# 78| 1: [IntLiteral] 0
-# 78| 0: [LTExpr] ... < ...
-# 78| 0: [LocalVariableAccess] access to local variable a
-# 78| 1: [LocalVariableAccess] access to local variable b
-# 79| 1: [BlockStmt] {...}
-# 80| 0: [ExprStmt] ...;
-# 80| 0: [PostIncrExpr] ...++
-# 80| 0: [LocalVariableAccess] access to local variable a
-# 83| 4: [ForStmt] for (...;...;...) ...
-# 84| 1: [BlockStmt] {...}
-# 89| 10: [Method] doWhile
-# 89| -1: [TypeMention] Void
-# 90| 4: [BlockStmt] {...}
-# 91| 0: [LocalVariableDeclStmt] ... ...;
-# 91| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
-# 91| -1: [TypeMention] int
-# 91| 0: [LocalVariableAccess] access to local variable x
-# 91| 1: [IntLiteral] 0
-# 92| 1: [DoStmt] do ... while (...);
-# 96| 0: [LTExpr] ... < ...
-# 96| 0: [LocalVariableAccess] access to local variable x
-# 96| 1: [IntLiteral] 10
-# 93| 1: [BlockStmt] {...}
-# 94| 0: [ExprStmt] ...;
-# 94| 0: [AssignExpr] ... = ...
-# 94| 0: [LocalVariableAccess] access to local variable x
-# 94| 1: [AddExpr] ... + ...
-# 94| 0: [LocalVariableAccess] access to local variable x
-# 94| 1: [IntLiteral] 1
-# 99| 11: [Method] checkedUnchecked
-# 99| -1: [TypeMention] Void
-# 100| 4: [BlockStmt] {...}
-# 101| 0: [LocalVariableDeclStmt] ... ...;
-# 101| 0: [LocalVariableDeclAndInitExpr] Int32 num = ...
-# 101| -1: [TypeMention] int
-# 101| 0: [LocalVariableAccess] access to local variable num
-# 101| 1: [MemberConstantAccess] access to constant MaxValue
-# 101| -1: [TypeAccess] access to type Int32
-# 101| 0: [TypeMention] int
-# 102| 1: [UncheckedStmt] unchecked {...}
-# 103| 0: [BlockStmt] {...}
-# 104| 0: [ExprStmt] ...;
-# 104| 0: [AssignExpr] ... = ...
-# 104| 0: [LocalVariableAccess] access to local variable num
-# 104| 1: [AddExpr] ... + ...
-# 104| 0: [LocalVariableAccess] access to local variable num
-# 104| 1: [IntLiteral] 1
-# 106| 2: [CheckedStmt] checked {...}
-# 107| 0: [BlockStmt] {...}
-# 108| 0: [ExprStmt] ...;
-# 108| 0: [AssignExpr] ... = ...
-# 108| 0: [LocalVariableAccess] access to local variable num
-# 108| 1: [AddExpr] ... + ...
-# 108| 0: [LocalVariableAccess] access to local variable num
-# 108| 1: [IntLiteral] 1
+# 71| 0: [LTExpr] ... < ...
+# 71| 0: [LocalVariableAccess] access to local variable i
+# 71| 1: [LocalVariableAccess] access to local variable j
+# 71| 1: [PostIncrExpr] ...++
+# 71| 0: [LocalVariableAccess] access to local variable i
+# 71| 2: [PostDecrExpr] ...--
+# 71| 0: [LocalVariableAccess] access to local variable j
+# 72| 3: [BlockStmt] {...}
+# 73| 0: [ExprStmt] ...;
+# 73| 0: [AssignExpr] ... = ...
+# 73| 0: [LocalVariableAccess] access to local variable x
+# 73| 1: [SubExpr] ... - ...
+# 73| 0: [LocalVariableAccess] access to local variable x
+# 73| 1: [IntLiteral] 1
+# 76| 2: [LocalVariableDeclStmt] ... ...;
+# 76| 0: [LocalVariableDeclExpr] Int32 a
+# 76| 0: [TypeMention] int
+# 76| 1: [LocalVariableDeclAndInitExpr] Int32 b = ...
+# 76| -1: [TypeMention] int
+# 76| 0: [LocalVariableAccess] access to local variable b
+# 76| 1: [IntLiteral] 10
+# 77| 3: [ForStmt] for (...;...;...) ...
+# 77| -1: [AssignExpr] ... = ...
+# 77| 0: [LocalVariableAccess] access to local variable a
+# 77| 1: [IntLiteral] 0
+# 77| 0: [LTExpr] ... < ...
+# 77| 0: [LocalVariableAccess] access to local variable a
+# 77| 1: [LocalVariableAccess] access to local variable b
+# 78| 1: [BlockStmt] {...}
+# 79| 0: [ExprStmt] ...;
+# 79| 0: [PostIncrExpr] ...++
+# 79| 0: [LocalVariableAccess] access to local variable a
+# 82| 4: [ForStmt] for (...;...;...) ...
+# 83| 1: [BlockStmt] {...}
+# 88| 10: [Method] doWhile
+# 88| -1: [TypeMention] Void
+# 89| 4: [BlockStmt] {...}
+# 90| 0: [LocalVariableDeclStmt] ... ...;
+# 90| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 90| -1: [TypeMention] int
+# 90| 0: [LocalVariableAccess] access to local variable x
+# 90| 1: [IntLiteral] 0
+# 91| 1: [DoStmt] do ... while (...);
+# 95| 0: [LTExpr] ... < ...
+# 95| 0: [LocalVariableAccess] access to local variable x
+# 95| 1: [IntLiteral] 10
+# 92| 1: [BlockStmt] {...}
+# 93| 0: [ExprStmt] ...;
+# 93| 0: [AssignExpr] ... = ...
+# 93| 0: [LocalVariableAccess] access to local variable x
+# 93| 1: [AddExpr] ... + ...
+# 93| 0: [LocalVariableAccess] access to local variable x
+# 93| 1: [IntLiteral] 1
+# 98| 11: [Method] checkedUnchecked
+# 98| -1: [TypeMention] Void
+# 99| 4: [BlockStmt] {...}
+# 100| 0: [LocalVariableDeclStmt] ... ...;
+# 100| 0: [LocalVariableDeclAndInitExpr] Int32 num = ...
+# 100| -1: [TypeMention] int
+# 100| 0: [LocalVariableAccess] access to local variable num
+# 100| 1: [MemberConstantAccess] access to constant MaxValue
+# 100| -1: [TypeAccess] access to type Int32
+# 100| 0: [TypeMention] int
+# 101| 1: [UncheckedStmt] unchecked {...}
+# 102| 0: [BlockStmt] {...}
+# 103| 0: [ExprStmt] ...;
+# 103| 0: [AssignExpr] ... = ...
+# 103| 0: [LocalVariableAccess] access to local variable num
+# 103| 1: [AddExpr] ... + ...
+# 103| 0: [LocalVariableAccess] access to local variable num
+# 103| 1: [IntLiteral] 1
+# 105| 2: [CheckedStmt] checked {...}
+# 106| 0: [BlockStmt] {...}
+# 107| 0: [ExprStmt] ...;
+# 107| 0: [AssignExpr] ... = ...
+# 107| 0: [LocalVariableAccess] access to local variable num
+# 107| 1: [AddExpr] ... + ...
+# 107| 0: [LocalVariableAccess] access to local variable num
+# 107| 1: [IntLiteral] 1
using.cs:
# 3| [Class] UsingStmt
# 5| 5: [Class] MyDisposable
diff --git a/csharp/ql/test/experimental/ir/ir/array.cs b/csharp/ql/test/experimental/ir/ir/array.cs
index a828e480848..d53a828ff54 100644
--- a/csharp/ql/test/experimental/ir/ir/array.cs
+++ b/csharp/ql/test/experimental/ir/ir/array.cs
@@ -20,4 +20,3 @@ public class ArrayTest {
e[1, 1] = -1;
}
}
-
diff --git a/csharp/ql/test/experimental/ir/ir/options b/csharp/ql/test/experimental/ir/ir/options
new file mode 100644
index 00000000000..c943386b4b8
--- /dev/null
+++ b/csharp/ql/test/experimental/ir/ir/options
@@ -0,0 +1 @@
+semmle-extractor-options: /langversion:preview
diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
index 5d3a1dfe6bf..bf639694da5 100644
--- a/csharp/ql/test/experimental/ir/ir/raw_ir.expected
+++ b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
@@ -1702,204 +1702,204 @@ stmts.cs:
# 40| mu40_4(Int32) = Store[#return] : &:r40_1, r40_3
#-----| Goto -> Block 1
-# 46| System.Void test_stmts.tryCatchFinally()
-# 46| Block 0
-# 46| v46_1(Void) = EnterFunction :
-# 46| mu46_2() = AliasedDefinition :
-# 48| r48_1(glval) = VariableAddress[x] :
-# 48| r48_2(Int32) = Constant[5] :
-# 48| mu48_3(Int32) = Store[x] : &:r48_1, r48_2
-# 51| r51_1(glval) = VariableAddress[x] :
-# 51| r51_2(Int32) = Load[x] : &:r51_1, ~m?
-# 51| r51_3(Int32) = Constant[0] :
-# 51| r51_4(Boolean) = CompareNE : r51_2, r51_3
-# 51| v51_5(Void) = ConditionalBranch : r51_4
+# 45| System.Void test_stmts.tryCatchFinally()
+# 45| Block 0
+# 45| v45_1(Void) = EnterFunction :
+# 45| mu45_2() = AliasedDefinition :
+# 47| r47_1(glval) = VariableAddress[x] :
+# 47| r47_2(Int32) = Constant[5] :
+# 47| mu47_3(Int32) = Store[x] : &:r47_1, r47_2
+# 50| r50_1(glval) = VariableAddress[x] :
+# 50| r50_2(Int32) = Load[x] : &:r50_1, ~m?
+# 50| r50_3(Int32) = Constant[0] :
+# 50| r50_4(Boolean) = CompareNE : r50_2, r50_3
+# 50| v50_5(Void) = ConditionalBranch : r50_4
#-----| False -> Block 4
#-----| True -> Block 3
-# 46| Block 1
-# 46| v46_3(Void) = AliasedUse : ~m?
-# 46| v46_4(Void) = ExitFunction :
+# 45| Block 1
+# 45| v45_3(Void) = AliasedUse : ~m?
+# 45| v45_4(Void) = ExitFunction :
-# 46| Block 2
-# 46| v46_5(Void) = Unwind :
+# 45| Block 2
+# 45| v45_5(Void) = Unwind :
#-----| Goto -> Block 1
-# 52| Block 3
-# 52| r52_1(glval) = VariableAddress[#throw52:17] :
-# 52| r52_2(Exception) = NewObj :
-# 52| r52_3() = FunctionAddress[Exception] :
-# 52| v52_4(Void) = Call[Exception] : func:r52_3, this:r52_2
-# 52| mu52_5() = ^CallSideEffect : ~m?
-# 52| mu52_6(Exception) = Store[#throw52:17] : &:r52_1, r52_2
-# 52| v52_7(Void) = ThrowValue : &:r52_1, ~m?
+# 51| Block 3
+# 51| r51_1(glval) = VariableAddress[#throw51:17] :
+# 51| r51_2(Exception) = NewObj :
+# 51| r51_3() = FunctionAddress[Exception] :
+# 51| v51_4(Void) = Call[Exception] : func:r51_3, this:r51_2
+# 51| mu51_5() = ^CallSideEffect : ~m?
+# 51| mu51_6(Exception) = Store[#throw51:17] : &:r51_1, r51_2
+# 51| v51_7(Void) = ThrowValue : &:r51_1, ~m?
#-----| Exception -> Block 6
-# 53| Block 4
-# 53| r53_1(Int32) = Constant[0] :
-# 53| r53_2(glval) = VariableAddress[x] :
-# 53| mu53_3(Int32) = Store[x] : &:r53_2, r53_1
+# 52| Block 4
+# 52| r52_1(Int32) = Constant[0] :
+# 52| r52_2(glval) = VariableAddress[x] :
+# 52| mu52_3(Int32) = Store[x] : &:r52_2, r52_1
#-----| Goto -> Block 5
-# 65| Block 5
-# 65| r65_1(Int32) = Constant[2] :
-# 65| r65_2(glval) = VariableAddress[x] :
-# 65| mu65_3(Int32) = Store[x] : &:r65_2, r65_1
-# 46| v46_6(Void) = ReturnVoid :
+# 64| Block 5
+# 64| r64_1(Int32) = Constant[2] :
+# 64| r64_2(glval) = VariableAddress[x] :
+# 64| mu64_3(Int32) = Store[x] : &:r64_2, r64_1
+# 45| v45_6(Void) = ReturnVoid :
#-----| Goto -> Block 1
-# 55| Block 6
-# 55| v55_1(Void) = CatchByType[Exception] :
+# 54| Block 6
+# 54| v54_1(Void) = CatchByType[Exception] :
#-----| Exception -> Block 8
#-----| Goto -> Block 7
-# 55| Block 7
-# 55| r55_2(glval) = VariableAddress[ex] :
-# 55| mu55_3(Exception) = Uninitialized[ex] : &:r55_2
-# 57| r57_1(Int32) = Constant[1] :
-# 57| r57_2(glval) = VariableAddress[x] :
-# 57| mu57_3(Int32) = Store[x] : &:r57_2, r57_1
+# 54| Block 7
+# 54| r54_2(glval) = VariableAddress[ex] :
+# 54| mu54_3(Exception) = Uninitialized[ex] : &:r54_2
+# 56| r56_1(Int32) = Constant[1] :
+# 56| r56_2(glval) = VariableAddress[x] :
+# 56| mu56_3(Int32) = Store[x] : &:r56_2, r56_1
#-----| Goto -> Block 5
-# 59| Block 8
-# 59| v59_1(Void) = CatchAny :
-# 61| v61_1(Void) = ReThrow :
+# 58| Block 8
+# 58| v58_1(Void) = CatchAny :
+# 60| v60_1(Void) = ReThrow :
#-----| Exception -> Block 2
-# 69| System.Void test_stmts.forStmt()
-# 69| Block 0
-# 69| v69_1(Void) = EnterFunction :
-# 69| mu69_2() = AliasedDefinition :
-# 71| r71_1(glval) = VariableAddress[x] :
+# 68| System.Void test_stmts.forStmt()
+# 68| Block 0
+# 68| v68_1(Void) = EnterFunction :
+# 68| mu68_2() = AliasedDefinition :
+# 70| r70_1(glval) = VariableAddress[x] :
+# 70| r70_2(Int32) = Constant[0] :
+# 70| mu70_3(Int32) = Store[x] : &:r70_1, r70_2
+# 71| r71_1(glval) = VariableAddress[i] :
# 71| r71_2(Int32) = Constant[0] :
-# 71| mu71_3(Int32) = Store[x] : &:r71_1, r71_2
-# 72| r72_1(glval) = VariableAddress[i] :
-# 72| r72_2(Int32) = Constant[0] :
-# 72| mu72_3(Int32) = Store[i] : &:r72_1, r72_2
-# 72| r72_4(glval) = VariableAddress[j] :
-# 72| r72_5(Int32) = Constant[10] :
-# 72| mu72_6(Int32) = Store[j] : &:r72_4, r72_5
+# 71| mu71_3(Int32) = Store[i] : &:r71_1, r71_2
+# 71| r71_4(glval) = VariableAddress[j] :
+# 71| r71_5(Int32) = Constant[10] :
+# 71| mu71_6(Int32) = Store[j] : &:r71_4, r71_5
#-----| Goto -> Block 2
-# 69| Block 1
-# 69| v69_3(Void) = ReturnVoid :
-# 69| v69_4(Void) = AliasedUse : ~m?
-# 69| v69_5(Void) = ExitFunction :
+# 68| Block 1
+# 68| v68_3(Void) = ReturnVoid :
+# 68| v68_4(Void) = AliasedUse : ~m?
+# 68| v68_5(Void) = ExitFunction :
-# 72| Block 2
-# 72| r72_7(glval) = VariableAddress[i] :
-# 72| r72_8(Int32) = Load[i] : &:r72_7, ~m?
-# 72| r72_9(glval) = VariableAddress[j] :
-# 72| r72_10(Int32) = Load[j] : &:r72_9, ~m?
-# 72| r72_11(Boolean) = CompareLT : r72_8, r72_10
-# 72| v72_12(Void) = ConditionalBranch : r72_11
+# 71| Block 2
+# 71| r71_7(glval) = VariableAddress[i] :
+# 71| r71_8(Int32) = Load[i] : &:r71_7, ~m?
+# 71| r71_9(glval) = VariableAddress[j] :
+# 71| r71_10(Int32) = Load[j] : &:r71_9, ~m?
+# 71| r71_11(Boolean) = CompareLT : r71_8, r71_10
+# 71| v71_12(Void) = ConditionalBranch : r71_11
#-----| False -> Block 4
#-----| True -> Block 3
-# 74| Block 3
-# 74| r74_1(glval) = VariableAddress[x] :
-# 74| r74_2(Int32) = Load[x] : &:r74_1, ~m?
-# 74| r74_3(Int32) = Constant[1] :
-# 74| r74_4(Int32) = Sub : r74_2, r74_3
-# 74| r74_5(glval) = VariableAddress[x] :
-# 74| mu74_6(Int32) = Store[x] : &:r74_5, r74_4
-# 72| r72_13(glval) = VariableAddress[i] :
-# 72| r72_14(Int32) = Load[i] : &:r72_13, ~m?
-# 72| r72_15(Int32) = Constant[1] :
-# 72| r72_16(Int32) = Add : r72_14, r72_15
-# 72| mu72_17(Int32) = Store[i] : &:r72_13, r72_16
-# 72| r72_18(glval) = VariableAddress[j] :
-# 72| r72_19(Int32) = Load[j] : &:r72_18, ~m?
-# 72| r72_20(Int32) = Constant[1] :
-# 72| r72_21(Int32) = Sub : r72_19, r72_20
-# 72| mu72_22(Int32) = Store[j] : &:r72_18, r72_21
+# 73| Block 3
+# 73| r73_1(glval) = VariableAddress[x] :
+# 73| r73_2(Int32) = Load[x] : &:r73_1, ~m?
+# 73| r73_3(Int32) = Constant[1] :
+# 73| r73_4(Int32) = Sub : r73_2, r73_3
+# 73| r73_5(glval) = VariableAddress[x] :
+# 73| mu73_6(Int32) = Store[x] : &:r73_5, r73_4
+# 71| r71_13(glval) = VariableAddress[i] :
+# 71| r71_14(Int32) = Load[i] : &:r71_13, ~m?
+# 71| r71_15(Int32) = Constant[1] :
+# 71| r71_16(Int32) = Add : r71_14, r71_15
+# 71| mu71_17(Int32) = Store[i] : &:r71_13, r71_16
+# 71| r71_18(glval) = VariableAddress[j] :
+# 71| r71_19(Int32) = Load[j] : &:r71_18, ~m?
+# 71| r71_20(Int32) = Constant[1] :
+# 71| r71_21(Int32) = Sub : r71_19, r71_20
+# 71| mu71_22(Int32) = Store[j] : &:r71_18, r71_21
#-----| Goto (back edge) -> Block 2
-# 77| Block 4
-# 77| r77_1(glval) = VariableAddress[a] :
-# 77| mu77_2(Int32) = Uninitialized[a] : &:r77_1
-# 77| r77_3(glval) = VariableAddress[b] :
-# 77| r77_4(Int32) = Constant[10] :
-# 77| mu77_5(Int32) = Store[b] : &:r77_3, r77_4
-# 78| r78_1(Int32) = Constant[0] :
-# 78| r78_2(glval) = VariableAddress[a] :
-# 78| mu78_3(Int32) = Store[a] : &:r78_2, r78_1
+# 76| Block 4
+# 76| r76_1(glval) = VariableAddress[a] :
+# 76| mu76_2(Int32) = Uninitialized[a] : &:r76_1
+# 76| r76_3(glval) = VariableAddress[b] :
+# 76| r76_4(Int32) = Constant[10] :
+# 76| mu76_5(Int32) = Store[b] : &:r76_3, r76_4
+# 77| r77_1(Int32) = Constant[0] :
+# 77| r77_2(glval) = VariableAddress[a] :
+# 77| mu77_3(Int32) = Store[a] : &:r77_2, r77_1
#-----| Goto -> Block 5
-# 78| Block 5
-# 78| r78_4(glval) = VariableAddress[a] :
-# 78| r78_5(Int32) = Load[a] : &:r78_4, ~m?
-# 78| r78_6(glval) = VariableAddress[b] :
-# 78| r78_7(Int32) = Load[b] : &:r78_6, ~m?
-# 78| r78_8(Boolean) = CompareLT : r78_5, r78_7
-# 78| v78_9(Void) = ConditionalBranch : r78_8
+# 77| Block 5
+# 77| r77_4(glval) = VariableAddress[a] :
+# 77| r77_5(Int32) = Load[a] : &:r77_4, ~m?
+# 77| r77_6(glval) = VariableAddress[b] :
+# 77| r77_7(Int32) = Load[b] : &:r77_6, ~m?
+# 77| r77_8(Boolean) = CompareLT : r77_5, r77_7
+# 77| v77_9(Void) = ConditionalBranch : r77_8
#-----| False -> Block 7
#-----| True -> Block 6
-# 80| Block 6
-# 80| r80_1(glval) = VariableAddress[a] :
-# 80| r80_2(Int32) = Load[a] : &:r80_1, ~m?
-# 80| r80_3(Int32) = Constant[1] :
-# 80| r80_4(Int32) = Add : r80_2, r80_3
-# 80| mu80_5(Int32) = Store[a] : &:r80_1, r80_4
+# 79| Block 6
+# 79| r79_1(glval) = VariableAddress[a] :
+# 79| r79_2(Int32) = Load[a] : &:r79_1, ~m?
+# 79| r79_3(Int32) = Constant[1] :
+# 79| r79_4(Int32) = Add : r79_2, r79_3
+# 79| mu79_5(Int32) = Store[a] : &:r79_1, r79_4
#-----| Goto (back edge) -> Block 5
-# 84| Block 7
-# 84| v84_1(Void) = NoOp :
+# 83| Block 7
+# 83| v83_1(Void) = NoOp :
#-----| Goto (back edge) -> Block 7
-# 89| System.Void test_stmts.doWhile()
-# 89| Block 0
-# 89| v89_1(Void) = EnterFunction :
-# 89| mu89_2() = AliasedDefinition :
-# 91| r91_1(glval) = VariableAddress[x] :
-# 91| r91_2(Int32) = Constant[0] :
-# 91| mu91_3(Int32) = Store[x] : &:r91_1, r91_2
+# 88| System.Void test_stmts.doWhile()
+# 88| Block 0
+# 88| v88_1(Void) = EnterFunction :
+# 88| mu88_2() = AliasedDefinition :
+# 90| r90_1(glval) = VariableAddress[x] :
+# 90| r90_2(Int32) = Constant[0] :
+# 90| mu90_3(Int32) = Store[x] : &:r90_1, r90_2
#-----| Goto -> Block 2
-# 89| Block 1
-# 89| v89_3(Void) = ReturnVoid :
-# 89| v89_4(Void) = AliasedUse : ~m?
-# 89| v89_5(Void) = ExitFunction :
+# 88| Block 1
+# 88| v88_3(Void) = ReturnVoid :
+# 88| v88_4(Void) = AliasedUse : ~m?
+# 88| v88_5(Void) = ExitFunction :
-# 94| Block 2
-# 94| r94_1(glval) = VariableAddress[x] :
-# 94| r94_2(Int32) = Load[x] : &:r94_1, ~m?
-# 94| r94_3(Int32) = Constant[1] :
-# 94| r94_4(Int32) = Add : r94_2, r94_3
-# 94| r94_5(glval) = VariableAddress[x] :
-# 94| mu94_6(Int32) = Store[x] : &:r94_5, r94_4
-# 96| r96_1(glval) = VariableAddress[x] :
-# 96| r96_2(Int32) = Load[x] : &:r96_1, ~m?
-# 96| r96_3(Int32) = Constant[10] :
-# 96| r96_4(Boolean) = CompareLT : r96_2, r96_3
-# 96| v96_5(Void) = ConditionalBranch : r96_4
+# 93| Block 2
+# 93| r93_1(glval) = VariableAddress[x] :
+# 93| r93_2(Int32) = Load[x] : &:r93_1, ~m?
+# 93| r93_3(Int32) = Constant[1] :
+# 93| r93_4(Int32) = Add : r93_2, r93_3
+# 93| r93_5(glval) = VariableAddress[x] :
+# 93| mu93_6(Int32) = Store[x] : &:r93_5, r93_4
+# 95| r95_1(glval) = VariableAddress[x] :
+# 95| r95_2(Int32) = Load[x] : &:r95_1, ~m?
+# 95| r95_3(Int32) = Constant[10] :
+# 95| r95_4(Boolean) = CompareLT : r95_2, r95_3
+# 95| v95_5(Void) = ConditionalBranch : r95_4
#-----| False -> Block 1
#-----| True (back edge) -> Block 2
-# 99| System.Void test_stmts.checkedUnchecked()
-# 99| Block 0
-# 99| v99_1(Void) = EnterFunction :
-# 99| mu99_2() = AliasedDefinition :
-# 101| r101_1(glval) = VariableAddress[num] :
-# 101| r101_2(Int32) = Constant[2147483647] :
-# 101| r101_3(Int32) = Load[?] : &:r101_2, ~m?
-# 101| mu101_4(Int32) = Store[num] : &:r101_1, r101_3
-# 104| r104_1(glval) = VariableAddress[num] :
-# 104| r104_2(Int32) = Load[num] : &:r104_1, ~m?
-# 104| r104_3(Int32) = Constant[1] :
-# 104| r104_4(Int32) = Add : r104_2, r104_3
-# 104| r104_5(glval) = VariableAddress[num] :
-# 104| mu104_6(Int32) = Store[num] : &:r104_5, r104_4
-# 108| r108_1(glval) = VariableAddress[num] :
-# 108| r108_2(Int32) = Load[num] : &:r108_1, ~m?
-# 108| r108_3(Int32) = Constant[1] :
-# 108| r108_4(Int32) = Add : r108_2, r108_3
-# 108| r108_5(glval) = VariableAddress[num] :
-# 108| mu108_6(Int32) = Store[num] : &:r108_5, r108_4
-# 99| v99_3(Void) = ReturnVoid :
-# 99| v99_4(Void) = AliasedUse : ~m?
-# 99| v99_5(Void) = ExitFunction :
+# 98| System.Void test_stmts.checkedUnchecked()
+# 98| Block 0
+# 98| v98_1(Void) = EnterFunction :
+# 98| mu98_2() = AliasedDefinition :
+# 100| r100_1(glval) = VariableAddress[num] :
+# 100| r100_2(Int32) = Constant[2147483647] :
+# 100| r100_3(Int32) = Load[?] : &:r100_2, ~m?
+# 100| mu100_4(Int32) = Store[num] : &:r100_1, r100_3
+# 103| r103_1(glval) = VariableAddress[num] :
+# 103| r103_2(Int32) = Load[num] : &:r103_1, ~m?
+# 103| r103_3(Int32) = Constant[1] :
+# 103| r103_4(Int32) = Add : r103_2, r103_3
+# 103| r103_5(glval) = VariableAddress[num] :
+# 103| mu103_6(Int32) = Store[num] : &:r103_5, r103_4
+# 107| r107_1(glval) = VariableAddress[num] :
+# 107| r107_2(Int32) = Load[num] : &:r107_1, ~m?
+# 107| r107_3(Int32) = Constant[1] :
+# 107| r107_4(Int32) = Add : r107_2, r107_3
+# 107| r107_5(glval) = VariableAddress[num] :
+# 107| mu107_6(Int32) = Store[num] : &:r107_5, r107_4
+# 98| v98_3(Void) = ReturnVoid :
+# 98| v98_4(Void) = AliasedUse : ~m?
+# 98| v98_5(Void) = ExitFunction :
using.cs:
# 7| System.Void UsingStmt.MyDisposable..ctor()
diff --git a/csharp/ql/test/experimental/ir/ir/stmts.cs b/csharp/ql/test/experimental/ir/ir/stmts.cs
index 00252205a2e..db0b523a434 100644
--- a/csharp/ql/test/experimental/ir/ir/stmts.cs
+++ b/csharp/ql/test/experimental/ir/ir/stmts.cs
@@ -42,7 +42,6 @@ public class test_stmts
return 0;
}
-
public static void tryCatchFinally()
{
int x = 5;
diff --git a/csharp/ql/test/experimental/ir/ir/using.cs b/csharp/ql/test/experimental/ir/ir/using.cs
index 7e5b9c47627..f81b2f128f1 100644
--- a/csharp/ql/test/experimental/ir/ir/using.cs
+++ b/csharp/ql/test/experimental/ir/ir/using.cs
@@ -26,5 +26,3 @@ class UsingStmt
o3.DoSomething();
}
}
-
-// semmle-extractor-options: /langversion:preview
diff --git a/csharp/ql/test/library-tests/aliases/Program.cs b/csharp/ql/test/library-tests/aliases/Program.cs
index 95a9a8611fe..d04b5ef6db0 100644
--- a/csharp/ql/test/library-tests/aliases/Program.cs
+++ b/csharp/ql/test/library-tests/aliases/Program.cs
@@ -1,6 +1,4 @@
/*
- semmle-extractor-options: /r:asm1=${testdir}/Assembly1.dll /r:asm2=${testdir}/Assembly2.dll
-
Class is defined in three places, and requires the alias to disambiguate them.
*/
diff --git a/csharp/ql/test/library-tests/aliases/aliases1.expected b/csharp/ql/test/library-tests/aliases/aliases1.expected
index 9417df43012..00b8969d949 100644
--- a/csharp/ql/test/library-tests/aliases/aliases1.expected
+++ b/csharp/ql/test/library-tests/aliases/aliases1.expected
@@ -1 +1 @@
-| Program.cs:10:7:10:11 | Class |
+| Program.cs:8:7:8:11 | Class |
diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected
index 50cfbf37f1e..7054a2ceeb0 100644
--- a/csharp/ql/test/library-tests/aliases/aliases2.expected
+++ b/csharp/ql/test/library-tests/aliases/aliases2.expected
@@ -1,3 +1,3 @@
-| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class |
-| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class |
-| Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class |
+| Program.cs:16:21:16:22 | c1 | Program.cs:8:7:8:11 | Class |
+| Program.cs:17:21:17:22 | c2 | Program.cs:8:7:8:11 | Class |
+| Program.cs:18:15:18:16 | c3 | Program.cs:8:7:8:11 | Class |
diff --git a/csharp/ql/test/library-tests/aliases/options b/csharp/ql/test/library-tests/aliases/options
new file mode 100644
index 00000000000..ba7ff6a5e31
--- /dev/null
+++ b/csharp/ql/test/library-tests/aliases/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:asm1=${testdir}/Assembly1.dll /r:asm2=${testdir}/Assembly2.dll
diff --git a/csharp/ql/test/library-tests/assemblies/Assemblies.cs b/csharp/ql/test/library-tests/assemblies/Assemblies.cs
index 452b45bf489..7197e561e46 100644
--- a/csharp/ql/test/library-tests/assemblies/Assemblies.cs
+++ b/csharp/ql/test/library-tests/assemblies/Assemblies.cs
@@ -14,5 +14,3 @@ namespace TestAssemblies
Locations.Test l = new Locations.Test();
}
}
-
-// semmle-extractor-options: /r:System.Runtime.Extensions.dll
diff --git a/csharp/ql/test/library-tests/assemblies/AssemblyInfo.cs b/csharp/ql/test/library-tests/assemblies/AssemblyInfo.cs
index 3cc48d8aa83..9ac1a6c0b2e 100644
--- a/csharp/ql/test/library-tests/assemblies/AssemblyInfo.cs
+++ b/csharp/ql/test/library-tests/assemblies/AssemblyInfo.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /out:Locations.dll
-
using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/csharp/ql/test/library-tests/assemblies/options b/csharp/ql/test/library-tests/assemblies/options
new file mode 100644
index 00000000000..4816fd4d60f
--- /dev/null
+++ b/csharp/ql/test/library-tests/assemblies/options
@@ -0,0 +1,2 @@
+semmle-extractor-options: /out:Locations.dll
+semmle-extractor-options: /r:System.Runtime.Extensions.dll
diff --git a/csharp/ql/test/library-tests/assignables/Assignables.cs b/csharp/ql/test/library-tests/assignables/Assignables.cs
index 33eb6f32826..9ddcb5f6f13 100644
--- a/csharp/ql/test/library-tests/assignables/Assignables.cs
+++ b/csharp/ql/test/library-tests/assignables/Assignables.cs
@@ -138,5 +138,3 @@ class Assignables
using var x = new System.IO.MemoryStream();
}
}
-
-// semmle-extractor-options: /langversion:8.0
diff --git a/csharp/ql/test/library-tests/assignables/options b/csharp/ql/test/library-tests/assignables/options
new file mode 100644
index 00000000000..3e262b5c3f2
--- /dev/null
+++ b/csharp/ql/test/library-tests/assignables/options
@@ -0,0 +1 @@
+semmle-extractor-options: /langversion:8.0
diff --git a/csharp/ql/test/library-tests/async/async.cs b/csharp/ql/test/library-tests/async/async.cs
index fefa85a85f3..3855e713271 100644
--- a/csharp/ql/test/library-tests/async/async.cs
+++ b/csharp/ql/test/library-tests/async/async.cs
@@ -54,5 +54,3 @@ namespace Semmle
}
}
}
-
-// semmle-extractor-options: /r:System.Runtime.Extensions.dll /r:System.IO.FileSystem.dll
diff --git a/csharp/ql/test/library-tests/async/options b/csharp/ql/test/library-tests/async/options
new file mode 100644
index 00000000000..a624a480883
--- /dev/null
+++ b/csharp/ql/test/library-tests/async/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Runtime.Extensions.dll /r:System.IO.FileSystem.dll
diff --git a/csharp/ql/test/library-tests/cil/attributes/Test.cs b/csharp/ql/test/library-tests/cil/attributes/Test.cs
index c72cfe0b0b3..2dfba697682 100644
--- a/csharp/ql/test/library-tests/cil/attributes/Test.cs
+++ b/csharp/ql/test/library-tests/cil/attributes/Test.cs
@@ -1,7 +1,5 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
{
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/cil/attributes/options b/csharp/ql/test/library-tests/cil/attributes/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/attributes/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/consistency/Program.cs b/csharp/ql/test/library-tests/cil/consistency/Program.cs
index ea38187bdec..e867fdc0718 100644
--- a/csharp/ql/test/library-tests/cil/consistency/Program.cs
+++ b/csharp/ql/test/library-tests/cil/consistency/Program.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
diff --git a/csharp/ql/test/library-tests/cil/consistency/options b/csharp/ql/test/library-tests/cil/consistency/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/consistency/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/dataflow/ControlFlow.expected b/csharp/ql/test/library-tests/cil/dataflow/ControlFlow.expected
index 628efe4d3d5..a21226e8376 100644
--- a/csharp/ql/test/library-tests/cil/dataflow/ControlFlow.expected
+++ b/csharp/ql/test/library-tests/cil/dataflow/ControlFlow.expected
@@ -1,2 +1,2 @@
-| dataflow.cs:57:9:57:18 | call to method DeadCode |
-| dataflow.cs:65:9:65:18 | call to method DeadCode |
+| dataflow.cs:55:9:55:18 | call to method DeadCode |
+| dataflow.cs:63:9:63:18 | call to method DeadCode |
diff --git a/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected b/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected
index 6b608808792..36dce892092 100644
--- a/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected
+++ b/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected
@@ -1,80 +1,80 @@
edges
-| dataflow.cs:18:18:18:26 | "tainted" : String | dataflow.cs:18:18:18:37 | call to method ToString |
-| dataflow.cs:20:27:20:27 | 2 : Int32 | dataflow.cs:20:18:20:31 | call to method Max |
-| dataflow.cs:20:30:20:30 | 3 : Int32 | dataflow.cs:20:18:20:31 | call to method Max |
-| dataflow.cs:21:29:21:31 | 0.5 : Double | dataflow.cs:21:18:21:32 | call to method Round |
-| dataflow.cs:22:45:22:53 | "tainted" : String | dataflow.cs:22:18:22:54 | call to method GetFullPath |
-| dataflow.cs:29:44:29:46 | 1 : Double | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
-| dataflow.cs:29:49:29:51 | 2 : Double | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
-| dataflow.cs:40:34:40:37 | "d1" : String | dataflow.cs:40:18:40:38 | call to method Taint1 |
-| dataflow.cs:41:34:41:37 | "d2" : String | dataflow.cs:41:18:41:38 | call to method Taint2 |
-| dataflow.cs:42:34:42:37 | "d3" : String | dataflow.cs:42:18:42:38 | call to method Taint3 |
-| dataflow.cs:46:28:46:32 | "t1a" : String | dataflow.cs:46:18:46:40 | call to method Taint1 |
-| dataflow.cs:46:35:46:39 | "t1b" : String | dataflow.cs:46:18:46:40 | call to method Taint1 |
-| dataflow.cs:49:35:49:38 | "t6" : String | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
-| dataflow.cs:49:41:49:44 | "t6" : String | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
-| dataflow.cs:74:21:74:34 | call to method NullFunction : null | dataflow.cs:74:21:74:52 | ... ?? ... |
-| dataflow.cs:74:39:74:52 | call to method IndirectNull : null | dataflow.cs:74:21:74:52 | ... ?? ... |
-| dataflow.cs:89:31:89:44 | call to method NullFunction : null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:74:39:74:52 | call to method IndirectNull : null |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:108:20:108:33 | call to method IndirectNull |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:108:20:108:33 | call to method IndirectNull : null |
-| dataflow.cs:108:20:108:33 | call to method IndirectNull : null | dataflow.cs:110:16:110:16 | access to local variable x : null |
-| dataflow.cs:109:23:109:26 | null : null | dataflow.cs:110:16:110:16 | access to local variable x : null |
-| dataflow.cs:110:16:110:16 | access to local variable x : null | dataflow.cs:74:21:74:34 | call to method NullFunction : null |
-| dataflow.cs:110:16:110:16 | access to local variable x : null | dataflow.cs:89:31:89:44 | call to method NullFunction : null |
+| dataflow.cs:16:18:16:26 | "tainted" : String | dataflow.cs:16:18:16:37 | call to method ToString |
+| dataflow.cs:18:27:18:27 | 2 : Int32 | dataflow.cs:18:18:18:31 | call to method Max |
+| dataflow.cs:18:30:18:30 | 3 : Int32 | dataflow.cs:18:18:18:31 | call to method Max |
+| dataflow.cs:19:29:19:31 | 0.5 : Double | dataflow.cs:19:18:19:32 | call to method Round |
+| dataflow.cs:20:45:20:53 | "tainted" : String | dataflow.cs:20:18:20:54 | call to method GetFullPath |
+| dataflow.cs:27:44:27:46 | 1 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
+| dataflow.cs:27:49:27:51 | 2 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
+| dataflow.cs:38:34:38:37 | "d1" : String | dataflow.cs:38:18:38:38 | call to method Taint1 |
+| dataflow.cs:39:34:39:37 | "d2" : String | dataflow.cs:39:18:39:38 | call to method Taint2 |
+| dataflow.cs:40:34:40:37 | "d3" : String | dataflow.cs:40:18:40:38 | call to method Taint3 |
+| dataflow.cs:44:28:44:32 | "t1a" : String | dataflow.cs:44:18:44:40 | call to method Taint1 |
+| dataflow.cs:44:35:44:39 | "t1b" : String | dataflow.cs:44:18:44:40 | call to method Taint1 |
+| dataflow.cs:47:35:47:38 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
+| dataflow.cs:47:41:47:44 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
+| dataflow.cs:72:21:72:34 | call to method NullFunction : null | dataflow.cs:72:21:72:52 | ... ?? ... |
+| dataflow.cs:72:39:72:52 | call to method IndirectNull : null | dataflow.cs:72:21:72:52 | ... ?? ... |
+| dataflow.cs:87:31:87:44 | call to method NullFunction : null | dataflow.cs:87:24:87:51 | ... ? ... : ... |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:72:39:72:52 | call to method IndirectNull : null |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:106:20:106:33 | call to method IndirectNull |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:106:20:106:33 | call to method IndirectNull : null |
+| dataflow.cs:106:20:106:33 | call to method IndirectNull : null | dataflow.cs:108:16:108:16 | access to local variable x : null |
+| dataflow.cs:107:23:107:26 | null : null | dataflow.cs:108:16:108:16 | access to local variable x : null |
+| dataflow.cs:108:16:108:16 | access to local variable x : null | dataflow.cs:72:21:72:34 | call to method NullFunction : null |
+| dataflow.cs:108:16:108:16 | access to local variable x : null | dataflow.cs:87:31:87:44 | call to method NullFunction : null |
nodes
-| dataflow.cs:18:18:18:26 | "tainted" : String | semmle.label | "tainted" : String |
-| dataflow.cs:18:18:18:37 | call to method ToString | semmle.label | call to method ToString |
-| dataflow.cs:20:18:20:31 | call to method Max | semmle.label | call to method Max |
-| dataflow.cs:20:27:20:27 | 2 : Int32 | semmle.label | 2 : Int32 |
-| dataflow.cs:20:30:20:30 | 3 : Int32 | semmle.label | 3 : Int32 |
-| dataflow.cs:21:18:21:32 | call to method Round | semmle.label | call to method Round |
-| dataflow.cs:21:29:21:31 | 0.5 : Double | semmle.label | 0.5 : Double |
-| dataflow.cs:22:18:22:54 | call to method GetFullPath | semmle.label | call to method GetFullPath |
-| dataflow.cs:22:45:22:53 | "tainted" : String | semmle.label | "tainted" : String |
-| dataflow.cs:29:18:29:52 | call to method IEEERemainder | semmle.label | call to method IEEERemainder |
-| dataflow.cs:29:44:29:46 | 1 : Double | semmle.label | 1 : Double |
-| dataflow.cs:29:49:29:51 | 2 : Double | semmle.label | 2 : Double |
-| dataflow.cs:40:18:40:38 | call to method Taint1 | semmle.label | call to method Taint1 |
-| dataflow.cs:40:34:40:37 | "d1" : String | semmle.label | "d1" : String |
-| dataflow.cs:41:18:41:38 | call to method Taint2 | semmle.label | call to method Taint2 |
-| dataflow.cs:41:34:41:37 | "d2" : String | semmle.label | "d2" : String |
-| dataflow.cs:42:18:42:38 | call to method Taint3 | semmle.label | call to method Taint3 |
-| dataflow.cs:42:34:42:37 | "d3" : String | semmle.label | "d3" : String |
-| dataflow.cs:46:18:46:40 | call to method Taint1 | semmle.label | call to method Taint1 |
-| dataflow.cs:46:28:46:32 | "t1a" : String | semmle.label | "t1a" : String |
-| dataflow.cs:46:35:46:39 | "t1b" : String | semmle.label | "t1b" : String |
-| dataflow.cs:49:18:49:45 | call to method TaintIndirect | semmle.label | call to method TaintIndirect |
-| dataflow.cs:49:35:49:38 | "t6" : String | semmle.label | "t6" : String |
-| dataflow.cs:49:41:49:44 | "t6" : String | semmle.label | "t6" : String |
-| dataflow.cs:74:21:74:34 | call to method NullFunction : null | semmle.label | call to method NullFunction : null |
-| dataflow.cs:74:21:74:52 | ... ?? ... | semmle.label | ... ?? ... |
-| dataflow.cs:74:39:74:52 | call to method IndirectNull : null | semmle.label | call to method IndirectNull : null |
-| dataflow.cs:89:24:89:51 | ... ? ... : ... | semmle.label | ... ? ... : ... |
-| dataflow.cs:89:31:89:44 | call to method NullFunction : null | semmle.label | call to method NullFunction : null |
-| dataflow.cs:102:30:102:33 | null : null | semmle.label | null : null |
-| dataflow.cs:108:20:108:33 | call to method IndirectNull | semmle.label | call to method IndirectNull |
-| dataflow.cs:108:20:108:33 | call to method IndirectNull : null | semmle.label | call to method IndirectNull : null |
-| dataflow.cs:109:23:109:26 | null : null | semmle.label | null : null |
-| dataflow.cs:110:16:110:16 | access to local variable x : null | semmle.label | access to local variable x : null |
+| dataflow.cs:16:18:16:26 | "tainted" : String | semmle.label | "tainted" : String |
+| dataflow.cs:16:18:16:37 | call to method ToString | semmle.label | call to method ToString |
+| dataflow.cs:18:18:18:31 | call to method Max | semmle.label | call to method Max |
+| dataflow.cs:18:27:18:27 | 2 : Int32 | semmle.label | 2 : Int32 |
+| dataflow.cs:18:30:18:30 | 3 : Int32 | semmle.label | 3 : Int32 |
+| dataflow.cs:19:18:19:32 | call to method Round | semmle.label | call to method Round |
+| dataflow.cs:19:29:19:31 | 0.5 : Double | semmle.label | 0.5 : Double |
+| dataflow.cs:20:18:20:54 | call to method GetFullPath | semmle.label | call to method GetFullPath |
+| dataflow.cs:20:45:20:53 | "tainted" : String | semmle.label | "tainted" : String |
+| dataflow.cs:27:18:27:52 | call to method IEEERemainder | semmle.label | call to method IEEERemainder |
+| dataflow.cs:27:44:27:46 | 1 : Double | semmle.label | 1 : Double |
+| dataflow.cs:27:49:27:51 | 2 : Double | semmle.label | 2 : Double |
+| dataflow.cs:38:18:38:38 | call to method Taint1 | semmle.label | call to method Taint1 |
+| dataflow.cs:38:34:38:37 | "d1" : String | semmle.label | "d1" : String |
+| dataflow.cs:39:18:39:38 | call to method Taint2 | semmle.label | call to method Taint2 |
+| dataflow.cs:39:34:39:37 | "d2" : String | semmle.label | "d2" : String |
+| dataflow.cs:40:18:40:38 | call to method Taint3 | semmle.label | call to method Taint3 |
+| dataflow.cs:40:34:40:37 | "d3" : String | semmle.label | "d3" : String |
+| dataflow.cs:44:18:44:40 | call to method Taint1 | semmle.label | call to method Taint1 |
+| dataflow.cs:44:28:44:32 | "t1a" : String | semmle.label | "t1a" : String |
+| dataflow.cs:44:35:44:39 | "t1b" : String | semmle.label | "t1b" : String |
+| dataflow.cs:47:18:47:45 | call to method TaintIndirect | semmle.label | call to method TaintIndirect |
+| dataflow.cs:47:35:47:38 | "t6" : String | semmle.label | "t6" : String |
+| dataflow.cs:47:41:47:44 | "t6" : String | semmle.label | "t6" : String |
+| dataflow.cs:72:21:72:34 | call to method NullFunction : null | semmle.label | call to method NullFunction : null |
+| dataflow.cs:72:21:72:52 | ... ?? ... | semmle.label | ... ?? ... |
+| dataflow.cs:72:39:72:52 | call to method IndirectNull : null | semmle.label | call to method IndirectNull : null |
+| dataflow.cs:87:24:87:51 | ... ? ... : ... | semmle.label | ... ? ... : ... |
+| dataflow.cs:87:31:87:44 | call to method NullFunction : null | semmle.label | call to method NullFunction : null |
+| dataflow.cs:100:30:100:33 | null : null | semmle.label | null : null |
+| dataflow.cs:106:20:106:33 | call to method IndirectNull | semmle.label | call to method IndirectNull |
+| dataflow.cs:106:20:106:33 | call to method IndirectNull : null | semmle.label | call to method IndirectNull : null |
+| dataflow.cs:107:23:107:26 | null : null | semmle.label | null : null |
+| dataflow.cs:108:16:108:16 | access to local variable x : null | semmle.label | access to local variable x : null |
#select
-| dataflow.cs:18:18:18:26 | "tainted" : String | dataflow.cs:18:18:18:37 | call to method ToString | dataflow.cs:18:18:18:37 | call to method ToString | $@ | dataflow.cs:18:18:18:37 | call to method ToString | call to method ToString |
-| dataflow.cs:20:27:20:27 | 2 : Int32 | dataflow.cs:20:18:20:31 | call to method Max | dataflow.cs:20:18:20:31 | call to method Max | $@ | dataflow.cs:20:18:20:31 | call to method Max | call to method Max |
-| dataflow.cs:20:30:20:30 | 3 : Int32 | dataflow.cs:20:18:20:31 | call to method Max | dataflow.cs:20:18:20:31 | call to method Max | $@ | dataflow.cs:20:18:20:31 | call to method Max | call to method Max |
-| dataflow.cs:21:29:21:31 | 0.5 : Double | dataflow.cs:21:18:21:32 | call to method Round | dataflow.cs:21:18:21:32 | call to method Round | $@ | dataflow.cs:21:18:21:32 | call to method Round | call to method Round |
-| dataflow.cs:22:45:22:53 | "tainted" : String | dataflow.cs:22:18:22:54 | call to method GetFullPath | dataflow.cs:22:18:22:54 | call to method GetFullPath | $@ | dataflow.cs:22:18:22:54 | call to method GetFullPath | call to method GetFullPath |
-| dataflow.cs:29:44:29:46 | 1 : Double | dataflow.cs:29:18:29:52 | call to method IEEERemainder | dataflow.cs:29:18:29:52 | call to method IEEERemainder | $@ | dataflow.cs:29:18:29:52 | call to method IEEERemainder | call to method IEEERemainder |
-| dataflow.cs:29:49:29:51 | 2 : Double | dataflow.cs:29:18:29:52 | call to method IEEERemainder | dataflow.cs:29:18:29:52 | call to method IEEERemainder | $@ | dataflow.cs:29:18:29:52 | call to method IEEERemainder | call to method IEEERemainder |
-| dataflow.cs:40:34:40:37 | "d1" : String | dataflow.cs:40:18:40:38 | call to method Taint1 | dataflow.cs:40:18:40:38 | call to method Taint1 | $@ | dataflow.cs:40:18:40:38 | call to method Taint1 | call to method Taint1 |
-| dataflow.cs:41:34:41:37 | "d2" : String | dataflow.cs:41:18:41:38 | call to method Taint2 | dataflow.cs:41:18:41:38 | call to method Taint2 | $@ | dataflow.cs:41:18:41:38 | call to method Taint2 | call to method Taint2 |
-| dataflow.cs:42:34:42:37 | "d3" : String | dataflow.cs:42:18:42:38 | call to method Taint3 | dataflow.cs:42:18:42:38 | call to method Taint3 | $@ | dataflow.cs:42:18:42:38 | call to method Taint3 | call to method Taint3 |
-| dataflow.cs:46:28:46:32 | "t1a" : String | dataflow.cs:46:18:46:40 | call to method Taint1 | dataflow.cs:46:18:46:40 | call to method Taint1 | $@ | dataflow.cs:46:18:46:40 | call to method Taint1 | call to method Taint1 |
-| dataflow.cs:46:35:46:39 | "t1b" : String | dataflow.cs:46:18:46:40 | call to method Taint1 | dataflow.cs:46:18:46:40 | call to method Taint1 | $@ | dataflow.cs:46:18:46:40 | call to method Taint1 | call to method Taint1 |
-| dataflow.cs:49:35:49:38 | "t6" : String | dataflow.cs:49:18:49:45 | call to method TaintIndirect | dataflow.cs:49:18:49:45 | call to method TaintIndirect | $@ | dataflow.cs:49:18:49:45 | call to method TaintIndirect | call to method TaintIndirect |
-| dataflow.cs:49:41:49:44 | "t6" : String | dataflow.cs:49:18:49:45 | call to method TaintIndirect | dataflow.cs:49:18:49:45 | call to method TaintIndirect | $@ | dataflow.cs:49:18:49:45 | call to method TaintIndirect | call to method TaintIndirect |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:74:21:74:52 | ... ?? ... | dataflow.cs:74:21:74:52 | ... ?? ... | $@ | dataflow.cs:74:21:74:52 | ... ?? ... | ... ?? ... |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:89:24:89:51 | ... ? ... : ... | dataflow.cs:89:24:89:51 | ... ? ... : ... | $@ | dataflow.cs:89:24:89:51 | ... ? ... : ... | ... ? ... : ... |
-| dataflow.cs:102:30:102:33 | null : null | dataflow.cs:108:20:108:33 | call to method IndirectNull | dataflow.cs:108:20:108:33 | call to method IndirectNull | $@ | dataflow.cs:108:20:108:33 | call to method IndirectNull | call to method IndirectNull |
-| dataflow.cs:109:23:109:26 | null : null | dataflow.cs:74:21:74:52 | ... ?? ... | dataflow.cs:74:21:74:52 | ... ?? ... | $@ | dataflow.cs:74:21:74:52 | ... ?? ... | ... ?? ... |
-| dataflow.cs:109:23:109:26 | null : null | dataflow.cs:89:24:89:51 | ... ? ... : ... | dataflow.cs:89:24:89:51 | ... ? ... : ... | $@ | dataflow.cs:89:24:89:51 | ... ? ... : ... | ... ? ... : ... |
+| dataflow.cs:16:18:16:26 | "tainted" : String | dataflow.cs:16:18:16:37 | call to method ToString | dataflow.cs:16:18:16:37 | call to method ToString | $@ | dataflow.cs:16:18:16:37 | call to method ToString | call to method ToString |
+| dataflow.cs:18:27:18:27 | 2 : Int32 | dataflow.cs:18:18:18:31 | call to method Max | dataflow.cs:18:18:18:31 | call to method Max | $@ | dataflow.cs:18:18:18:31 | call to method Max | call to method Max |
+| dataflow.cs:18:30:18:30 | 3 : Int32 | dataflow.cs:18:18:18:31 | call to method Max | dataflow.cs:18:18:18:31 | call to method Max | $@ | dataflow.cs:18:18:18:31 | call to method Max | call to method Max |
+| dataflow.cs:19:29:19:31 | 0.5 : Double | dataflow.cs:19:18:19:32 | call to method Round | dataflow.cs:19:18:19:32 | call to method Round | $@ | dataflow.cs:19:18:19:32 | call to method Round | call to method Round |
+| dataflow.cs:20:45:20:53 | "tainted" : String | dataflow.cs:20:18:20:54 | call to method GetFullPath | dataflow.cs:20:18:20:54 | call to method GetFullPath | $@ | dataflow.cs:20:18:20:54 | call to method GetFullPath | call to method GetFullPath |
+| dataflow.cs:27:44:27:46 | 1 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder | dataflow.cs:27:18:27:52 | call to method IEEERemainder | $@ | dataflow.cs:27:18:27:52 | call to method IEEERemainder | call to method IEEERemainder |
+| dataflow.cs:27:49:27:51 | 2 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder | dataflow.cs:27:18:27:52 | call to method IEEERemainder | $@ | dataflow.cs:27:18:27:52 | call to method IEEERemainder | call to method IEEERemainder |
+| dataflow.cs:38:34:38:37 | "d1" : String | dataflow.cs:38:18:38:38 | call to method Taint1 | dataflow.cs:38:18:38:38 | call to method Taint1 | $@ | dataflow.cs:38:18:38:38 | call to method Taint1 | call to method Taint1 |
+| dataflow.cs:39:34:39:37 | "d2" : String | dataflow.cs:39:18:39:38 | call to method Taint2 | dataflow.cs:39:18:39:38 | call to method Taint2 | $@ | dataflow.cs:39:18:39:38 | call to method Taint2 | call to method Taint2 |
+| dataflow.cs:40:34:40:37 | "d3" : String | dataflow.cs:40:18:40:38 | call to method Taint3 | dataflow.cs:40:18:40:38 | call to method Taint3 | $@ | dataflow.cs:40:18:40:38 | call to method Taint3 | call to method Taint3 |
+| dataflow.cs:44:28:44:32 | "t1a" : String | dataflow.cs:44:18:44:40 | call to method Taint1 | dataflow.cs:44:18:44:40 | call to method Taint1 | $@ | dataflow.cs:44:18:44:40 | call to method Taint1 | call to method Taint1 |
+| dataflow.cs:44:35:44:39 | "t1b" : String | dataflow.cs:44:18:44:40 | call to method Taint1 | dataflow.cs:44:18:44:40 | call to method Taint1 | $@ | dataflow.cs:44:18:44:40 | call to method Taint1 | call to method Taint1 |
+| dataflow.cs:47:35:47:38 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect | dataflow.cs:47:18:47:45 | call to method TaintIndirect | $@ | dataflow.cs:47:18:47:45 | call to method TaintIndirect | call to method TaintIndirect |
+| dataflow.cs:47:41:47:44 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect | dataflow.cs:47:18:47:45 | call to method TaintIndirect | $@ | dataflow.cs:47:18:47:45 | call to method TaintIndirect | call to method TaintIndirect |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:72:21:72:52 | ... ?? ... | dataflow.cs:72:21:72:52 | ... ?? ... | $@ | dataflow.cs:72:21:72:52 | ... ?? ... | ... ?? ... |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:87:24:87:51 | ... ? ... : ... | dataflow.cs:87:24:87:51 | ... ? ... : ... | $@ | dataflow.cs:87:24:87:51 | ... ? ... : ... | ... ? ... : ... |
+| dataflow.cs:100:30:100:33 | null : null | dataflow.cs:106:20:106:33 | call to method IndirectNull | dataflow.cs:106:20:106:33 | call to method IndirectNull | $@ | dataflow.cs:106:20:106:33 | call to method IndirectNull | call to method IndirectNull |
+| dataflow.cs:107:23:107:26 | null : null | dataflow.cs:72:21:72:52 | ... ?? ... | dataflow.cs:72:21:72:52 | ... ?? ... | $@ | dataflow.cs:72:21:72:52 | ... ?? ... | ... ?? ... |
+| dataflow.cs:107:23:107:26 | null : null | dataflow.cs:87:24:87:51 | ... ? ... : ... | dataflow.cs:87:24:87:51 | ... ? ... : ... | $@ | dataflow.cs:87:24:87:51 | ... ? ... : ... | ... ? ... : ... |
diff --git a/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected b/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected
index f9f0d31b5cb..e434ebf9c48 100644
--- a/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected
+++ b/csharp/ql/test/library-tests/cil/dataflow/Nullness.expected
@@ -1,42 +1,42 @@
alwaysNull
-| dataflow.cs:70:21:70:35 | default(...) |
-| dataflow.cs:74:21:74:34 | call to method NullFunction |
-| dataflow.cs:74:21:74:52 | ... ?? ... |
-| dataflow.cs:74:39:74:52 | call to method IndirectNull |
-| dataflow.cs:78:21:78:45 | call to method ReturnsNull |
-| dataflow.cs:79:21:79:46 | call to method ReturnsNull2 |
-| dataflow.cs:80:21:80:44 | access to property NullProperty |
-| dataflow.cs:89:31:89:44 | call to method NullFunction |
+| dataflow.cs:68:21:68:35 | default(...) |
+| dataflow.cs:72:21:72:34 | call to method NullFunction |
+| dataflow.cs:72:21:72:52 | ... ?? ... |
+| dataflow.cs:72:39:72:52 | call to method IndirectNull |
+| dataflow.cs:76:21:76:45 | call to method ReturnsNull |
+| dataflow.cs:77:21:77:46 | call to method ReturnsNull2 |
+| dataflow.cs:78:21:78:44 | access to property NullProperty |
+| dataflow.cs:87:31:87:44 | call to method NullFunction |
alwaysNotNull
-| dataflow.cs:71:13:71:20 | access to local variable nonNull1 |
-| dataflow.cs:71:13:71:35 | Int32 nonNull1 = ... |
-| dataflow.cs:71:24:71:35 | default(...) |
-| dataflow.cs:71:32:71:34 | access to type Int32 |
-| dataflow.cs:72:27:72:30 | this access |
-| dataflow.cs:72:27:72:40 | call to method GetType |
-| dataflow.cs:73:30:73:33 | true |
-| dataflow.cs:73:30:73:44 | call to method ToString |
-| dataflow.cs:74:21:74:34 | this access |
-| dataflow.cs:74:39:74:52 | this access |
-| dataflow.cs:77:27:77:52 | object creation of type NullMethods |
+| dataflow.cs:69:13:69:20 | access to local variable nonNull1 |
+| dataflow.cs:69:13:69:35 | Int32 nonNull1 = ... |
+| dataflow.cs:69:24:69:35 | default(...) |
+| dataflow.cs:69:32:69:34 | access to type Int32 |
+| dataflow.cs:70:27:70:30 | this access |
+| dataflow.cs:70:27:70:40 | call to method GetType |
+| dataflow.cs:71:30:71:33 | true |
+| dataflow.cs:71:30:71:44 | call to method ToString |
+| dataflow.cs:72:21:72:34 | this access |
+| dataflow.cs:72:39:72:52 | this access |
+| dataflow.cs:75:27:75:52 | object creation of type NullMethods |
+| dataflow.cs:76:21:76:31 | access to local variable nullMethods |
+| dataflow.cs:77:21:77:31 | access to local variable nullMethods |
| dataflow.cs:78:21:78:31 | access to local variable nullMethods |
-| dataflow.cs:79:21:79:31 | access to local variable nullMethods |
-| dataflow.cs:80:21:80:31 | access to local variable nullMethods |
-| dataflow.cs:83:23:83:51 | object creation of type NonNullMethods |
+| dataflow.cs:81:23:81:51 | object creation of type NonNullMethods |
+| dataflow.cs:82:24:82:30 | access to local variable nonNull |
+| dataflow.cs:82:24:82:47 | call to method ReturnsNonNull |
+| dataflow.cs:83:24:83:30 | access to local variable nonNull |
+| dataflow.cs:83:24:83:55 | call to method ReturnsNonNullIndirect |
| dataflow.cs:84:24:84:30 | access to local variable nonNull |
-| dataflow.cs:84:24:84:47 | call to method ReturnsNonNull |
-| dataflow.cs:85:24:85:30 | access to local variable nonNull |
-| dataflow.cs:85:24:85:55 | call to method ReturnsNonNullIndirect |
-| dataflow.cs:86:24:86:30 | access to local variable nonNull |
-| dataflow.cs:89:24:89:27 | access to field cond |
-| dataflow.cs:89:24:89:27 | this access |
-| dataflow.cs:89:31:89:44 | this access |
-| dataflow.cs:89:48:89:51 | this access |
-| dataflow.cs:90:24:90:34 | access to local variable nullMethods |
-| dataflow.cs:91:24:91:34 | access to local variable nullMethods |
-| dataflow.cs:92:26:92:32 | access to local variable nonNull |
-| dataflow.cs:95:25:95:31 | access to local variable nonNull |
-| dataflow.cs:96:26:96:32 | access to local variable nonNull |
-| dataflow.cs:97:32:97:73 | object creation of type MaybeNullMethods |
-| dataflow.cs:98:21:98:36 | access to local variable maybeNullMethods |
-| dataflow.cs:99:22:99:37 | access to local variable maybeNullMethods |
+| dataflow.cs:87:24:87:27 | access to field cond |
+| dataflow.cs:87:24:87:27 | this access |
+| dataflow.cs:87:31:87:44 | this access |
+| dataflow.cs:87:48:87:51 | this access |
+| dataflow.cs:88:24:88:34 | access to local variable nullMethods |
+| dataflow.cs:89:24:89:34 | access to local variable nullMethods |
+| dataflow.cs:90:26:90:32 | access to local variable nonNull |
+| dataflow.cs:93:25:93:31 | access to local variable nonNull |
+| dataflow.cs:94:26:94:32 | access to local variable nonNull |
+| dataflow.cs:95:32:95:73 | object creation of type MaybeNullMethods |
+| dataflow.cs:96:21:96:36 | access to local variable maybeNullMethods |
+| dataflow.cs:97:22:97:37 | access to local variable maybeNullMethods |
diff --git a/csharp/ql/test/library-tests/cil/dataflow/TaintTracking.expected b/csharp/ql/test/library-tests/cil/dataflow/TaintTracking.expected
index 2bcd26c9063..ef25cee2190 100644
--- a/csharp/ql/test/library-tests/cil/dataflow/TaintTracking.expected
+++ b/csharp/ql/test/library-tests/cil/dataflow/TaintTracking.expected
@@ -1,28 +1,28 @@
-| dataflow.cs:11:18:11:22 | "123" | dataflow.cs:11:18:11:37 | call to method CompareTo |
-| dataflow.cs:11:34:11:36 | "b" | dataflow.cs:11:18:11:37 | call to method CompareTo |
-| dataflow.cs:18:18:18:26 | "tainted" | dataflow.cs:18:18:18:37 | call to method ToString |
-| dataflow.cs:20:27:20:27 | 2 | dataflow.cs:20:18:20:31 | call to method Max |
-| dataflow.cs:20:30:20:30 | 3 | dataflow.cs:20:18:20:31 | call to method Max |
-| dataflow.cs:21:29:21:31 | 0.5 | dataflow.cs:21:18:21:32 | call to method Round |
-| dataflow.cs:22:45:22:53 | "tainted" | dataflow.cs:22:18:22:54 | call to method GetFullPath |
-| dataflow.cs:26:37:26:37 | 1 | dataflow.cs:26:18:26:56 | call to method DivRem |
-| dataflow.cs:26:40:26:40 | 2 | dataflow.cs:26:18:26:56 | call to method DivRem |
-| dataflow.cs:29:44:29:46 | 1 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
-| dataflow.cs:29:49:29:51 | 2 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
-| dataflow.cs:32:60:32:60 | 1 | dataflow.cs:32:18:32:80 | call to method DivRem |
-| dataflow.cs:32:63:32:63 | 2 | dataflow.cs:32:18:32:80 | call to method DivRem |
-| dataflow.cs:40:34:40:37 | "d1" | dataflow.cs:40:18:40:38 | call to method Taint1 |
-| dataflow.cs:41:34:41:37 | "d2" | dataflow.cs:41:18:41:38 | call to method Taint2 |
-| dataflow.cs:42:34:42:37 | "d3" | dataflow.cs:42:18:42:38 | call to method Taint3 |
-| dataflow.cs:46:28:46:32 | "t1a" | dataflow.cs:46:18:46:40 | call to method Taint1 |
-| dataflow.cs:46:35:46:39 | "t1b" | dataflow.cs:46:18:46:40 | call to method Taint1 |
-| dataflow.cs:47:28:47:28 | 2 | dataflow.cs:47:18:47:32 | call to method Taint2 |
-| dataflow.cs:47:31:47:31 | 3 | dataflow.cs:47:18:47:32 | call to method Taint2 |
-| dataflow.cs:48:28:48:28 | 1 | dataflow.cs:48:18:48:29 | call to method Taint3 |
-| dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
-| dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
-| dataflow.cs:102:30:102:33 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
-| dataflow.cs:102:30:102:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
-| dataflow.cs:102:30:102:33 | null | dataflow.cs:108:20:108:33 | call to method IndirectNull |
-| dataflow.cs:109:23:109:26 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
-| dataflow.cs:109:23:109:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
+| dataflow.cs:9:18:9:22 | "123" | dataflow.cs:9:18:9:37 | call to method CompareTo |
+| dataflow.cs:9:34:9:36 | "b" | dataflow.cs:9:18:9:37 | call to method CompareTo |
+| dataflow.cs:16:18:16:26 | "tainted" | dataflow.cs:16:18:16:37 | call to method ToString |
+| dataflow.cs:18:27:18:27 | 2 | dataflow.cs:18:18:18:31 | call to method Max |
+| dataflow.cs:18:30:18:30 | 3 | dataflow.cs:18:18:18:31 | call to method Max |
+| dataflow.cs:19:29:19:31 | 0.5 | dataflow.cs:19:18:19:32 | call to method Round |
+| dataflow.cs:20:45:20:53 | "tainted" | dataflow.cs:20:18:20:54 | call to method GetFullPath |
+| dataflow.cs:24:37:24:37 | 1 | dataflow.cs:24:18:24:56 | call to method DivRem |
+| dataflow.cs:24:40:24:40 | 2 | dataflow.cs:24:18:24:56 | call to method DivRem |
+| dataflow.cs:27:44:27:46 | 1 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
+| dataflow.cs:27:49:27:51 | 2 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
+| dataflow.cs:30:60:30:60 | 1 | dataflow.cs:30:18:30:80 | call to method DivRem |
+| dataflow.cs:30:63:30:63 | 2 | dataflow.cs:30:18:30:80 | call to method DivRem |
+| dataflow.cs:38:34:38:37 | "d1" | dataflow.cs:38:18:38:38 | call to method Taint1 |
+| dataflow.cs:39:34:39:37 | "d2" | dataflow.cs:39:18:39:38 | call to method Taint2 |
+| dataflow.cs:40:34:40:37 | "d3" | dataflow.cs:40:18:40:38 | call to method Taint3 |
+| dataflow.cs:44:28:44:32 | "t1a" | dataflow.cs:44:18:44:40 | call to method Taint1 |
+| dataflow.cs:44:35:44:39 | "t1b" | dataflow.cs:44:18:44:40 | call to method Taint1 |
+| dataflow.cs:45:28:45:28 | 2 | dataflow.cs:45:18:45:32 | call to method Taint2 |
+| dataflow.cs:45:31:45:31 | 3 | dataflow.cs:45:18:45:32 | call to method Taint2 |
+| dataflow.cs:46:28:46:28 | 1 | dataflow.cs:46:18:46:29 | call to method Taint3 |
+| dataflow.cs:47:35:47:38 | "t6" | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
+| dataflow.cs:47:41:47:44 | "t6" | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
+| dataflow.cs:100:30:100:33 | null | dataflow.cs:72:21:72:52 | ... ?? ... |
+| dataflow.cs:100:30:100:33 | null | dataflow.cs:87:24:87:51 | ... ? ... : ... |
+| dataflow.cs:100:30:100:33 | null | dataflow.cs:106:20:106:33 | call to method IndirectNull |
+| dataflow.cs:107:23:107:26 | null | dataflow.cs:72:21:72:52 | ... ?? ... |
+| dataflow.cs:107:23:107:26 | null | dataflow.cs:87:24:87:51 | ... ? ... : ... |
diff --git a/csharp/ql/test/library-tests/cil/dataflow/dataflow.cs b/csharp/ql/test/library-tests/cil/dataflow/dataflow.cs
index a8a76332157..af26fc0ed12 100644
--- a/csharp/ql/test/library-tests/cil/dataflow/dataflow.cs
+++ b/csharp/ql/test/library-tests/cil/dataflow/dataflow.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
diff --git a/csharp/ql/test/library-tests/cil/dataflow/options b/csharp/ql/test/library-tests/cil/dataflow/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/dataflow/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/enums/Program.cs b/csharp/ql/test/library-tests/cil/enums/Program.cs
index ea38187bdec..e867fdc0718 100644
--- a/csharp/ql/test/library-tests/cil/enums/Program.cs
+++ b/csharp/ql/test/library-tests/cil/enums/Program.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
diff --git a/csharp/ql/test/library-tests/cil/enums/options b/csharp/ql/test/library-tests/cil/enums/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/enums/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/functionPointers/Test.cs b/csharp/ql/test/library-tests/cil/functionPointers/Test.cs
index c72cfe0b0b3..2dfba697682 100644
--- a/csharp/ql/test/library-tests/cil/functionPointers/Test.cs
+++ b/csharp/ql/test/library-tests/cil/functionPointers/Test.cs
@@ -1,7 +1,5 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
{
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/cil/functionPointers/options b/csharp/ql/test/library-tests/cil/functionPointers/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/functionPointers/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/init-only-prop/Program.cs b/csharp/ql/test/library-tests/cil/init-only-prop/Program.cs
index ea38187bdec..e867fdc0718 100644
--- a/csharp/ql/test/library-tests/cil/init-only-prop/Program.cs
+++ b/csharp/ql/test/library-tests/cil/init-only-prop/Program.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
diff --git a/csharp/ql/test/library-tests/cil/init-only-prop/options b/csharp/ql/test/library-tests/cil/init-only-prop/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/init-only-prop/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/pdbs/Pdbs.cs b/csharp/ql/test/library-tests/cil/pdbs/Pdbs.cs
index 1157d04dab2..8b137891791 100644
--- a/csharp/ql/test/library-tests/cil/pdbs/Pdbs.cs
+++ b/csharp/ql/test/library-tests/cil/pdbs/Pdbs.cs
@@ -1 +1 @@
-// semmle-extractor-options: --cil --pdb
+
diff --git a/csharp/ql/test/library-tests/cil/pdbs/options b/csharp/ql/test/library-tests/cil/pdbs/options
new file mode 100644
index 00000000000..0771fbd3771
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/pdbs/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil --pdb
diff --git a/csharp/ql/test/library-tests/cil/regressions/Methods.cs b/csharp/ql/test/library-tests/cil/regressions/Methods.cs
index b81a5c9a44f..7d8ec90f84d 100644
--- a/csharp/ql/test/library-tests/cil/regressions/Methods.cs
+++ b/csharp/ql/test/library-tests/cil/regressions/Methods.cs
@@ -1,11 +1,9 @@
-/*
+/*
* A regression test for the CIL extractor - compiled into Methods.dll
* This tests the correct extraction of F, and we should end up with
* 2 constructed methods of F.
*/
-// semmle-extractor-options: --cil
-
namespace Methods
{
public class Class1
diff --git a/csharp/ql/test/library-tests/cil/regressions/options b/csharp/ql/test/library-tests/cil/regressions/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/regressions/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/cil/typeAnnotations/Program.cs b/csharp/ql/test/library-tests/cil/typeAnnotations/Program.cs
index ea38187bdec..e867fdc0718 100644
--- a/csharp/ql/test/library-tests/cil/typeAnnotations/Program.cs
+++ b/csharp/ql/test/library-tests/cil/typeAnnotations/Program.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil
-
using System;
class Test
diff --git a/csharp/ql/test/library-tests/cil/typeAnnotations/options b/csharp/ql/test/library-tests/cil/typeAnnotations/options
new file mode 100644
index 00000000000..8511aa162b8
--- /dev/null
+++ b/csharp/ql/test/library-tests/cil/typeAnnotations/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil
diff --git a/csharp/ql/test/library-tests/comments/BindingAfter.expected b/csharp/ql/test/library-tests/comments/BindingAfter.expected
index 59b784aa196..5ab21cb1106 100644
--- a/csharp/ql/test/library-tests/comments/BindingAfter.expected
+++ b/csharp/ql/test/library-tests/comments/BindingAfter.expected
@@ -2,17 +2,17 @@
| comments1.cs:4:1:4:25 | // ... | comments1.cs:9:7:9:7 | C | 1) Basic comment types |
| comments1.cs:6:1:6:24 | // ... | comments1.cs:9:7:9:7 | C | A single-line comment |
| comments1.cs:8:1:8:18 | /// ... | comments1.cs:9:7:9:7 | C | An XML comment |
-| comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:35:7:35:9 | Foo | A multiline comment |
-| comments1.cs:14:1:14:20 | // ... | comments1.cs:35:7:35:9 | Foo | 2) Comment blocks |
-| comments1.cs:16:1:16:38 | // ... | comments1.cs:35:7:35:9 | Foo | A line on its own is a commentblock |
-| comments1.cs:18:1:19:31 | // ... | comments1.cs:35:7:35:9 | Foo | Two lines together |
-| comments1.cs:21:1:23:15 | // ... | comments1.cs:35:7:35:9 | Foo | Three lines |
-| comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:35:7:35:9 | Foo | This is a |
-| comments1.cs:27:1:29:13 | /* ... */ | comments1.cs:35:7:35:9 | Foo | This is a |
-| comments1.cs:31:1:33:30 | // ... | comments1.cs:35:7:35:9 | Foo | These three lines, |
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:40:9:40:9 | x | |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:43:9:43:9 | y | as this line |
-| comments1.cs:43:15:43:36 | // ... | comments1.cs:44:9:44:9 | z | These are different |
+| comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:34:7:34:9 | Foo | A multiline comment |
+| comments1.cs:13:1:13:20 | // ... | comments1.cs:34:7:34:9 | Foo | 2) Comment blocks |
+| comments1.cs:15:1:15:38 | // ... | comments1.cs:34:7:34:9 | Foo | A line on its own is a commentblock |
+| comments1.cs:17:1:18:31 | // ... | comments1.cs:34:7:34:9 | Foo | Two lines together |
+| comments1.cs:20:1:22:15 | // ... | comments1.cs:34:7:34:9 | Foo | Three lines |
+| comments1.cs:24:1:24:43 | /* ... */ | comments1.cs:34:7:34:9 | Foo | This is a |
+| comments1.cs:26:1:28:13 | /* ... */ | comments1.cs:34:7:34:9 | Foo | This is a |
+| comments1.cs:30:1:32:30 | // ... | comments1.cs:34:7:34:9 | Foo | These three lines, |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:39:9:39:9 | x | |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:42:9:42:9 | y | as this line |
+| comments1.cs:42:15:42:36 | // ... | comments1.cs:43:9:43:9 | z | These are different |
| comments2.cs:1:1:2:15 | // ... | comments2.cs:11:7:11:8 | C2 | Start of comment2.cs |
| comments2.cs:5:27:5:41 | // ... | comments2.cs:11:7:11:8 | C2 | Unassociated |
| comments2.cs:8:1:8:15 | // ... | comments2.cs:11:7:11:8 | C2 | Unassociated |
diff --git a/csharp/ql/test/library-tests/comments/BindingBefore.expected b/csharp/ql/test/library-tests/comments/BindingBefore.expected
index 9cb36b9e7cc..a3af22ce982 100644
--- a/csharp/ql/test/library-tests/comments/BindingBefore.expected
+++ b/csharp/ql/test/library-tests/comments/BindingBefore.expected
@@ -1,15 +1,15 @@
| comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:9:7:9:7 | C | A multiline comment |
-| comments1.cs:14:1:14:20 | // ... | comments1.cs:9:7:9:7 | C | 2) Comment blocks |
-| comments1.cs:16:1:16:38 | // ... | comments1.cs:9:7:9:7 | C | A line on its own is a commentblock |
-| comments1.cs:18:1:19:31 | // ... | comments1.cs:9:7:9:7 | C | Two lines together |
-| comments1.cs:21:1:23:15 | // ... | comments1.cs:9:7:9:7 | C | Three lines |
-| comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:9:7:9:7 | C | This is a |
-| comments1.cs:27:1:29:13 | /* ... */ | comments1.cs:9:7:9:7 | C | This is a |
-| comments1.cs:31:1:33:30 | // ... | comments1.cs:9:7:9:7 | C | These three lines, |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:40:9:40:9 | x | as this line |
-| comments1.cs:43:15:43:36 | // ... | comments1.cs:43:9:43:9 | y | These are different |
-| comments1.cs:44:15:44:32 | // ... | comments1.cs:44:9:44:9 | z | comment blocks. |
-| comments1.cs:47:1:47:21 | // ... | comments1.cs:35:7:35:9 | Foo | End of comment1.cs |
+| comments1.cs:13:1:13:20 | // ... | comments1.cs:9:7:9:7 | C | 2) Comment blocks |
+| comments1.cs:15:1:15:38 | // ... | comments1.cs:9:7:9:7 | C | A line on its own is a commentblock |
+| comments1.cs:17:1:18:31 | // ... | comments1.cs:9:7:9:7 | C | Two lines together |
+| comments1.cs:20:1:22:15 | // ... | comments1.cs:9:7:9:7 | C | Three lines |
+| comments1.cs:24:1:24:43 | /* ... */ | comments1.cs:9:7:9:7 | C | This is a |
+| comments1.cs:26:1:28:13 | /* ... */ | comments1.cs:9:7:9:7 | C | This is a |
+| comments1.cs:30:1:32:30 | // ... | comments1.cs:9:7:9:7 | C | These three lines, |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:39:9:39:9 | x | as this line |
+| comments1.cs:42:15:42:36 | // ... | comments1.cs:42:9:42:9 | y | These are different |
+| comments1.cs:43:15:43:32 | // ... | comments1.cs:43:9:43:9 | z | comment blocks. |
+| comments1.cs:46:1:46:21 | // ... | comments1.cs:34:7:34:9 | Foo | End of comment1.cs |
| comments2.cs:13:17:13:25 | // ... | comments2.cs:13:9:13:14 | field1 | field1 |
| comments2.cs:14:17:14:25 | // ... | comments2.cs:14:9:14:14 | field2 | field2 |
| comments2.cs:16:5:16:9 | // ... | comments2.cs:14:9:14:14 | field2 | C2 |
diff --git a/csharp/ql/test/library-tests/comments/BindingParent.expected b/csharp/ql/test/library-tests/comments/BindingParent.expected
index d9c8f24d48d..440c0606292 100644
--- a/csharp/ql/test/library-tests/comments/BindingParent.expected
+++ b/csharp/ql/test/library-tests/comments/BindingParent.expected
@@ -1,7 +1,7 @@
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:35:7:35:9 | Foo | |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:35:7:35:9 | Foo | as this line |
-| comments1.cs:43:15:43:36 | // ... | comments1.cs:35:7:35:9 | Foo | These are different |
-| comments1.cs:44:15:44:32 | // ... | comments1.cs:35:7:35:9 | Foo | comment blocks. |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:34:7:34:9 | Foo | |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:34:7:34:9 | Foo | as this line |
+| comments1.cs:42:15:42:36 | // ... | comments1.cs:34:7:34:9 | Foo | These are different |
+| comments1.cs:43:15:43:32 | // ... | comments1.cs:34:7:34:9 | Foo | comment blocks. |
| comments2.cs:13:17:13:25 | // ... | comments2.cs:11:7:11:8 | C2 | field1 |
| comments2.cs:14:17:14:25 | // ... | comments2.cs:11:7:11:8 | C2 | field2 |
| comments2.cs:16:5:16:9 | // ... | comments2.cs:11:7:11:8 | C2 | C2 |
diff --git a/csharp/ql/test/library-tests/comments/Bindings.expected b/csharp/ql/test/library-tests/comments/Bindings.expected
index 6822c9411a6..301f83f2978 100644
--- a/csharp/ql/test/library-tests/comments/Bindings.expected
+++ b/csharp/ql/test/library-tests/comments/Bindings.expected
@@ -1,8 +1,8 @@
| comments1.cs:8:1:8:18 | /// ... | comments1.cs:9:7:9:7 | C | An XML comment |
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:40:9:40:9 | x | |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:40:9:40:9 | x | as this line |
-| comments1.cs:43:15:43:36 | // ... | comments1.cs:43:9:43:9 | y | These are different |
-| comments1.cs:44:15:44:32 | // ... | comments1.cs:44:9:44:9 | z | comment blocks. |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:39:9:39:9 | x | |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:39:9:39:9 | x | as this line |
+| comments1.cs:42:15:42:36 | // ... | comments1.cs:42:9:42:9 | y | These are different |
+| comments1.cs:43:15:43:32 | // ... | comments1.cs:43:9:43:9 | z | comment blocks. |
| comments2.cs:10:1:10:6 | /// ... | comments2.cs:11:7:11:8 | C2 | C2 |
| comments2.cs:13:17:13:25 | // ... | comments2.cs:13:9:13:14 | field1 | field1 |
| comments2.cs:14:17:14:25 | // ... | comments2.cs:14:9:14:14 | field2 | field2 |
diff --git a/csharp/ql/test/library-tests/comments/Comments.expected b/csharp/ql/test/library-tests/comments/Comments.expected
index a0ff83a59be..1a7d3db234b 100644
--- a/csharp/ql/test/library-tests/comments/Comments.expected
+++ b/csharp/ql/test/library-tests/comments/Comments.expected
@@ -3,20 +3,20 @@ singlelineComment
| comments1.cs:1:1:2:46 | // ... | comments1.cs:2:1:2:46 | // ... | 2 | This tests the basic types of comment block | // This tests the basic types of comment block |
| comments1.cs:4:1:4:25 | // ... | comments1.cs:4:1:4:25 | // ... | 1 | 1) Basic comment types | // 1) Basic comment types |
| comments1.cs:6:1:6:24 | // ... | comments1.cs:6:1:6:24 | // ... | 1 | A single-line comment | // A single-line comment |
-| comments1.cs:14:1:14:20 | // ... | comments1.cs:14:1:14:20 | // ... | 1 | 2) Comment blocks | // 2) Comment blocks |
-| comments1.cs:16:1:16:38 | // ... | comments1.cs:16:1:16:38 | // ... | 1 | A line on its own is a commentblock | // A line on its own is a commentblock |
-| comments1.cs:18:1:19:31 | // ... | comments1.cs:18:1:18:21 | // ... | 2 | Two lines together | // Two lines together |
-| comments1.cs:18:1:19:31 | // ... | comments1.cs:19:1:19:31 | // ... | 2 | are in the same commentblock | // are in the same commentblock |
-| comments1.cs:21:1:23:15 | // ... | comments1.cs:21:1:21:14 | // ... | 3 | Three lines | // Three lines |
-| comments1.cs:21:1:23:15 | // ... | comments1.cs:22:1:22:14 | // ... | 3 | in the same | // in the same |
-| comments1.cs:21:1:23:15 | // ... | comments1.cs:23:1:23:15 | // ... | 3 | commentblock | // commentblock |
-| comments1.cs:31:1:33:30 | // ... | comments1.cs:31:1:31:21 | // ... | 3 | These three lines, | // These three lines, |
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:39:5:39:41 | // ... | 3 | This is not the same comment block | // This is not the same comment block |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:40:13:40:27 | // ... | 2 | as this line | // as this line |
-| comments1.cs:40:13:41:51 | // ... | comments1.cs:41:13:41:51 | // ... | 2 | because they are offset differently. | // because they are offset differently. |
-| comments1.cs:43:15:43:36 | // ... | comments1.cs:43:15:43:36 | // ... | 1 | These are different | // These are different |
-| comments1.cs:44:15:44:32 | // ... | comments1.cs:44:15:44:32 | // ... | 1 | comment blocks. | // comment blocks. |
-| comments1.cs:47:1:47:21 | // ... | comments1.cs:47:1:47:21 | // ... | 1 | End of comment1.cs | // End of comment1.cs |
+| comments1.cs:13:1:13:20 | // ... | comments1.cs:13:1:13:20 | // ... | 1 | 2) Comment blocks | // 2) Comment blocks |
+| comments1.cs:15:1:15:38 | // ... | comments1.cs:15:1:15:38 | // ... | 1 | A line on its own is a commentblock | // A line on its own is a commentblock |
+| comments1.cs:17:1:18:31 | // ... | comments1.cs:17:1:17:21 | // ... | 2 | Two lines together | // Two lines together |
+| comments1.cs:17:1:18:31 | // ... | comments1.cs:18:1:18:31 | // ... | 2 | are in the same commentblock | // are in the same commentblock |
+| comments1.cs:20:1:22:15 | // ... | comments1.cs:20:1:20:14 | // ... | 3 | Three lines | // Three lines |
+| comments1.cs:20:1:22:15 | // ... | comments1.cs:21:1:21:14 | // ... | 3 | in the same | // in the same |
+| comments1.cs:20:1:22:15 | // ... | comments1.cs:22:1:22:15 | // ... | 3 | commentblock | // commentblock |
+| comments1.cs:30:1:32:30 | // ... | comments1.cs:30:1:30:21 | // ... | 3 | These three lines, | // These three lines, |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:38:5:38:41 | // ... | 3 | This is not the same comment block | // This is not the same comment block |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:39:13:39:27 | // ... | 2 | as this line | // as this line |
+| comments1.cs:39:13:40:51 | // ... | comments1.cs:40:13:40:51 | // ... | 2 | because they are offset differently. | // because they are offset differently. |
+| comments1.cs:42:15:42:36 | // ... | comments1.cs:42:15:42:36 | // ... | 1 | These are different | // These are different |
+| comments1.cs:43:15:43:32 | // ... | comments1.cs:43:15:43:32 | // ... | 1 | comment blocks. | // comment blocks. |
+| comments1.cs:46:1:46:21 | // ... | comments1.cs:46:1:46:21 | // ... | 1 | End of comment1.cs | // End of comment1.cs |
| comments2.cs:1:1:2:15 | // ... | comments2.cs:1:1:1:23 | // ... | 2 | Start of comment2.cs | // Start of comment2.cs |
| comments2.cs:1:1:2:15 | // ... | comments2.cs:2:1:2:15 | // ... | 2 | Unassociated | // Unassociated |
| comments2.cs:5:27:5:41 | // ... | comments2.cs:5:27:5:41 | // ... | 1 | Unassociated | // Unassociated |
@@ -86,15 +86,15 @@ singlelineComment
| trivia.cs:57:27:57:87 | // ... | trivia.cs:57:27:57:87 | // ... | 1 | Restores the nullable warning context to project settings. | // Restores the nullable warning context to project settings. |
multilineComment
| comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:11:1:11:25 | /* ... */ | 1 | A multiline comment | /* A multiline comment */ |
-| comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:25:1:25:15 | /* ... */ | 2 | This is a | /* This is a */ |
-| comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:25:18:25:43 | /* ... */ | 2 | single comment block | /* single comment block */ |
-| comments1.cs:27:1:29:13 | /* ... */ | comments1.cs:27:1:27:12 | /* ... */ | 3 | This is a | /* This is a |
-| comments1.cs:27:1:29:13 | /* ... */ | comments1.cs:28:1:28:17 | /* ... */ | 3 | true multiline | true multiline |
-| comments1.cs:27:1:29:13 | /* ... */ | comments1.cs:29:1:29:13 | /* ... */ | 3 | comment | comment */ |
-| comments1.cs:31:1:33:30 | // ... | comments1.cs:32:1:32:61 | /* ... */ | 3 | even though they are using different commenting styles, | /* even though they are using different commenting styles, */ |
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:37:5:37:6 | /* ... */ | 3 | | /* |
-| comments1.cs:37:5:39:41 | /* ... */ | comments1.cs:38:1:38:6 | /* ... */ | 3 | | */ |
+| comments1.cs:24:1:24:43 | /* ... */ | comments1.cs:24:1:24:15 | /* ... */ | 2 | This is a | /* This is a */ |
+| comments1.cs:24:1:24:43 | /* ... */ | comments1.cs:24:18:24:43 | /* ... */ | 2 | single comment block | /* single comment block */ |
+| comments1.cs:26:1:28:13 | /* ... */ | comments1.cs:26:1:26:12 | /* ... */ | 3 | This is a | /* This is a |
+| comments1.cs:26:1:28:13 | /* ... */ | comments1.cs:27:1:27:17 | /* ... */ | 3 | true multiline | true multiline |
+| comments1.cs:26:1:28:13 | /* ... */ | comments1.cs:28:1:28:13 | /* ... */ | 3 | comment | comment */ |
+| comments1.cs:30:1:32:30 | // ... | comments1.cs:31:1:31:61 | /* ... */ | 3 | even though they are using different commenting styles, | /* even though they are using different commenting styles, */ |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:36:5:36:6 | /* ... */ | 3 | | /* |
+| comments1.cs:36:5:38:41 | /* ... */ | comments1.cs:37:1:37:6 | /* ... */ | 3 | | */ |
xmlComment
| comments1.cs:8:1:8:18 | /// ... | comments1.cs:8:1:8:18 | /// ... | 1 | An XML comment | /// An XML comment |
-| comments1.cs:31:1:33:30 | // ... | comments1.cs:33:1:33:30 | /// ... | 3 | form a single commentblock | /// form a single commentblock |
+| comments1.cs:30:1:32:30 | // ... | comments1.cs:32:1:32:30 | /// ... | 3 | form a single commentblock | /// form a single commentblock |
| comments2.cs:10:1:10:6 | /// ... | comments2.cs:10:1:10:6 | /// ... | 1 | C2 | /// C2 |
diff --git a/csharp/ql/test/library-tests/comments/DefineDirectives.expected b/csharp/ql/test/library-tests/comments/DefineDirectives.expected
index e58b3859d58..79cdc468e92 100644
--- a/csharp/ql/test/library-tests/comments/DefineDirectives.expected
+++ b/csharp/ql/test/library-tests/comments/DefineDirectives.expected
@@ -1 +1,2 @@
| trivia.cs:4:1:4:13 | #define ... | DEBUG |
+| trivia.cs:5:1:5:14 | #define ... | DEBUG2 |
diff --git a/csharp/ql/test/library-tests/comments/Directives.expected b/csharp/ql/test/library-tests/comments/Directives.expected
index c6d0a12ffb6..01b418ba754 100644
--- a/csharp/ql/test/library-tests/comments/Directives.expected
+++ b/csharp/ql/test/library-tests/comments/Directives.expected
@@ -1,5 +1,6 @@
directives
| trivia.cs:4:1:4:13 | #define ... | trivia.cs:4:1:4:13 | trivia.cs:4:1:4:13 | active |
+| trivia.cs:5:1:5:14 | #define ... | trivia.cs:5:1:5:14 | trivia.cs:5:1:5:14 | active |
| trivia.cs:6:1:6:12 | #undef ... | trivia.cs:6:1:6:12 | trivia.cs:6:1:6:12 | active |
| trivia.cs:12:1:12:35 | #pragma warning ... | trivia.cs:12:1:12:35 | trivia.cs:12:1:12:35 | active |
| trivia.cs:13:1:13:103 | #pragma checksum ... | trivia.cs:13:1:13:103 | trivia.cs:13:1:13:103 | active |
@@ -29,8 +30,15 @@ directives
| trivia.cs:72:1:72:43 | #warning ... | trivia.cs:72:1:72:43 | trivia.cs:72:1:72:43 | active |
| trivia.cs:74:1:74:5 | #else | trivia.cs:74:1:74:5 | trivia.cs:74:1:74:5 | active |
| trivia.cs:76:1:76:6 | #endif | trivia.cs:76:1:76:6 | trivia.cs:76:1:76:6 | active |
+| trivia.cs:82:1:82:10 | #if ... | trivia.cs:82:1:82:10 | trivia.cs:82:1:82:10 | active |
+| trivia.cs:86:1:86:6 | #endif | trivia.cs:86:1:86:6 | trivia.cs:86:1:86:6 | active |
+| trivia.cs:93:1:93:10 | #if ... | trivia.cs:93:1:93:10 | trivia.cs:93:1:93:10 | active |
+| trivia.cs:95:1:95:6 | #endif | trivia.cs:95:1:95:6 | trivia.cs:95:1:95:6 | active |
+| trivia.cs:103:1:103:10 | #if ... | trivia.cs:103:1:103:10 | trivia.cs:103:1:103:10 | active |
+| trivia.cs:105:1:105:6 | #endif | trivia.cs:105:1:105:6 | trivia.cs:105:1:105:6 | active |
comp
| trivia.cs:4:1:4:13 | #define ... | compilation |
+| trivia.cs:5:1:5:14 | #define ... | compilation |
| trivia.cs:6:1:6:12 | #undef ... | compilation |
| trivia.cs:12:1:12:35 | #pragma warning ... | compilation |
| trivia.cs:13:1:13:103 | #pragma checksum ... | compilation |
@@ -60,3 +68,9 @@ comp
| trivia.cs:72:1:72:43 | #warning ... | compilation |
| trivia.cs:74:1:74:5 | #else | compilation |
| trivia.cs:76:1:76:6 | #endif | compilation |
+| trivia.cs:82:1:82:10 | #if ... | compilation |
+| trivia.cs:86:1:86:6 | #endif | compilation |
+| trivia.cs:93:1:93:10 | #if ... | compilation |
+| trivia.cs:95:1:95:6 | #endif | compilation |
+| trivia.cs:103:1:103:10 | #if ... | compilation |
+| trivia.cs:105:1:105:6 | #endif | compilation |
diff --git a/csharp/ql/test/library-tests/comments/IfDirectives.expected b/csharp/ql/test/library-tests/comments/IfDirectives.expected
index 3a3a24ef798..3b7b24e388a 100644
--- a/csharp/ql/test/library-tests/comments/IfDirectives.expected
+++ b/csharp/ql/test/library-tests/comments/IfDirectives.expected
@@ -1,6 +1,9 @@
ifDirectives
| trivia.cs:65:1:65:9 | #if ... | trivia.cs:76:1:76:6 | #endif | not taken | false | trivia.cs:65:5:65:9 | DEBUG |
| trivia.cs:68:1:68:10 | #if ... | trivia.cs:70:1:70:6 | #endif | not taken | false | trivia.cs:68:5:68:10 | NESTED |
+| trivia.cs:82:1:82:10 | #if ... | trivia.cs:86:1:86:6 | #endif | taken | true | trivia.cs:82:5:82:10 | DEBUG2 |
+| trivia.cs:93:1:93:10 | #if ... | trivia.cs:95:1:95:6 | #endif | taken | true | trivia.cs:93:5:93:10 | DEBUG2 |
+| trivia.cs:103:1:103:10 | #if ... | trivia.cs:105:1:105:6 | #endif | taken | true | trivia.cs:103:5:103:10 | DEBUG2 |
siblings
| trivia.cs:65:1:65:9 | #if ... | trivia.cs:71:1:71:35 | #elif ... | 0 | taken |
| trivia.cs:65:1:65:9 | #if ... | trivia.cs:74:1:74:5 | #else | 1 | not taken |
@@ -8,6 +11,9 @@ conditionalDirectives
| trivia.cs:65:1:65:9 | #if ... | not taken | false | trivia.cs:65:5:65:9 | DEBUG |
| trivia.cs:68:1:68:10 | #if ... | not taken | false | trivia.cs:68:5:68:10 | NESTED |
| trivia.cs:71:1:71:35 | #elif ... | taken | true | trivia.cs:71:7:71:35 | ... \|\| ... |
+| trivia.cs:82:1:82:10 | #if ... | taken | true | trivia.cs:82:5:82:10 | DEBUG2 |
+| trivia.cs:93:1:93:10 | #if ... | taken | true | trivia.cs:93:5:93:10 | DEBUG2 |
+| trivia.cs:103:1:103:10 | #if ... | taken | true | trivia.cs:103:5:103:10 | DEBUG2 |
expressions
| trivia.cs:65:5:65:9 | DEBUG |
| trivia.cs:68:5:68:10 | NESTED |
@@ -17,3 +23,6 @@ expressions
| trivia.cs:71:20:71:23 | true |
| trivia.cs:71:29:71:35 | !... |
| trivia.cs:71:31:71:34 | TEST |
+| trivia.cs:82:5:82:10 | DEBUG2 |
+| trivia.cs:93:5:93:10 | DEBUG2 |
+| trivia.cs:103:5:103:10 | DEBUG2 |
diff --git a/csharp/ql/test/library-tests/comments/Orphans.expected b/csharp/ql/test/library-tests/comments/Orphans.expected
index 56e5af20cd2..f0568fda4e3 100644
--- a/csharp/ql/test/library-tests/comments/Orphans.expected
+++ b/csharp/ql/test/library-tests/comments/Orphans.expected
@@ -2,14 +2,14 @@
| comments1.cs:4:1:4:25 | // ... |
| comments1.cs:6:1:6:24 | // ... |
| comments1.cs:11:1:11:25 | /* ... */ |
-| comments1.cs:14:1:14:20 | // ... |
-| comments1.cs:16:1:16:38 | // ... |
-| comments1.cs:18:1:19:31 | // ... |
-| comments1.cs:21:1:23:15 | // ... |
-| comments1.cs:25:1:25:43 | /* ... */ |
-| comments1.cs:27:1:29:13 | /* ... */ |
-| comments1.cs:31:1:33:30 | // ... |
-| comments1.cs:47:1:47:21 | // ... |
+| comments1.cs:13:1:13:20 | // ... |
+| comments1.cs:15:1:15:38 | // ... |
+| comments1.cs:17:1:18:31 | // ... |
+| comments1.cs:20:1:22:15 | // ... |
+| comments1.cs:24:1:24:43 | /* ... */ |
+| comments1.cs:26:1:28:13 | /* ... */ |
+| comments1.cs:30:1:32:30 | // ... |
+| comments1.cs:46:1:46:21 | // ... |
| comments2.cs:1:1:2:15 | // ... |
| comments2.cs:5:27:5:41 | // ... |
| comments2.cs:8:1:8:15 | // ... |
diff --git a/csharp/ql/test/library-tests/comments/PrintAst.expected b/csharp/ql/test/library-tests/comments/PrintAst.expected
index 71d16cdf134..1ac1ffb67b7 100644
--- a/csharp/ql/test/library-tests/comments/PrintAst.expected
+++ b/csharp/ql/test/library-tests/comments/PrintAst.expected
@@ -1,12 +1,12 @@
comments1.cs:
# 9| [Class] C
-# 35| [Class] Foo
-# 40| 5: [Field] x
-# 40| -1: [TypeMention] int
-# 43| 6: [Field] y
+# 34| [Class] Foo
+# 39| 5: [Field] x
+# 39| -1: [TypeMention] int
+# 42| 6: [Field] y
+# 42| -1: [TypeMention] int
+# 43| 7: [Field] z
# 43| -1: [TypeMention] int
-# 44| 7: [Field] z
-# 44| -1: [TypeMention] int
comments2.cs:
# 11| [Class] C2
# 13| 4: [Field] field1
@@ -177,3 +177,32 @@ trivia.cs:
# 73| -1: [TypeMention] int
# 73| 0: [LocalVariableAccess] access to local variable i
# 73| 1: [IntLiteral] 1
+# 80| [Class] Tr5
+# 83| 5: [Method] M1
+# 83| -1: [TypeMention] Void
+# 84| 4: [BlockStmt] {...}
+# 88| 6: [Method] M2
+# 88| -1: [TypeMention] Void
+# 89| 4: [BlockStmt] {...}
+# 92| 7: [Field] F1
+# 92| -1: [TypeMention] int
+# 92| 1: [AssignExpr] ... = ...
+# 92| 0: [FieldAccess] access to field F1
+# 94| 1: [IntLiteral] 10
+# 98| 8: [Field] F2
+# 98| -1: [TypeMention] int
+# 98| 1: [AssignExpr] ... = ...
+# 98| 0: [FieldAccess] access to field F2
+# 98| 1: [IntLiteral] 0
+# 100| 9: [Property] P1
+# 100| -1: [TypeMention] int
+# 102| 3: [Getter] get_P1
+# 104| 4: [Setter] set_P1
+#-----| 2: (Parameters)
+# 104| 0: [Parameter] value
+# 108| 10: [Property] P2
+# 108| -1: [TypeMention] int
+# 108| 3: [Getter] get_P2
+# 108| 4: [Setter] set_P2
+#-----| 2: (Parameters)
+# 108| 0: [Parameter] value
diff --git a/csharp/ql/test/library-tests/comments/comments1.cs b/csharp/ql/test/library-tests/comments/comments1.cs
index 62c45ea50dc..e984c988908 100644
--- a/csharp/ql/test/library-tests/comments/comments1.cs
+++ b/csharp/ql/test/library-tests/comments/comments1.cs
@@ -10,7 +10,6 @@ class C { }
/* A multiline comment */
-
// 2) Comment blocks
// A line on its own is a commentblock
diff --git a/csharp/ql/test/library-tests/comments/trivia.cs b/csharp/ql/test/library-tests/comments/trivia.cs
index be670eac1c4..fe3f217c393 100644
--- a/csharp/ql/test/library-tests/comments/trivia.cs
+++ b/csharp/ql/test/library-tests/comments/trivia.cs
@@ -2,7 +2,7 @@
// Start of trivia.cs
// Unassociated
#define DEBUG
-
+#define DEBUG2
#undef DEBUG
using System;
@@ -75,4 +75,35 @@ class Tr4
var i = 2;
#endif
}
-}
\ No newline at end of file
+}
+
+class Tr5
+{
+#if DEBUG2
+ static void M1()
+ {
+ }
+#endif
+
+ static void M2()
+ {
+ }
+
+ public int F1
+#if DEBUG2
+= 10
+#endif
+;
+
+ public int F2 = 0;
+
+ public int P1
+ {
+ get;
+#if DEBUG2
+ set;
+#endif
+ }
+
+ public int P2 { get; set; }
+}
diff --git a/csharp/ql/test/library-tests/commons/Assertions/Assertions.cs b/csharp/ql/test/library-tests/commons/Assertions/Assertions.cs
index 871625b7e7c..e6e7cae1f37 100644
--- a/csharp/ql/test/library-tests/commons/Assertions/Assertions.cs
+++ b/csharp/ql/test/library-tests/commons/Assertions/Assertions.cs
@@ -51,5 +51,3 @@ class Assertions
Contract.Assume(s != null, "s is non-null");
}
}
-
-// semmle-extractor-options: ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs /r:System.Diagnostics.Contracts.dll
diff --git a/csharp/ql/test/library-tests/commons/Assertions/options b/csharp/ql/test/library-tests/commons/Assertions/options
new file mode 100644
index 00000000000..4aa2084a2a8
--- /dev/null
+++ b/csharp/ql/test/library-tests/commons/Assertions/options
@@ -0,0 +1 @@
+semmle-extractor-options: ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs /r:System.Diagnostics.Contracts.dll
diff --git a/csharp/ql/test/library-tests/commons/Disposal/Disposal.cs b/csharp/ql/test/library-tests/commons/Disposal/Disposal.cs
index 8082bc50f09..4bbd4acc9f4 100644
--- a/csharp/ql/test/library-tests/commons/Disposal/Disposal.cs
+++ b/csharp/ql/test/library-tests/commons/Disposal/Disposal.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: --cil /r:System.Net.Http.dll /r:System.Runtime.Extensions.dll /r:System.Private.Xml.dll
-
using System;
class Disposal : IDisposable
diff --git a/csharp/ql/test/library-tests/commons/Disposal/DisposedVariables.expected b/csharp/ql/test/library-tests/commons/Disposal/DisposedVariables.expected
index 6d4526eabe2..e3c8b6886cb 100644
--- a/csharp/ql/test/library-tests/commons/Disposal/DisposedVariables.expected
+++ b/csharp/ql/test/library-tests/commons/Disposal/DisposedVariables.expected
@@ -1,5 +1,5 @@
-| Disposal.cs:7:17:7:22 | field1 |
-| Disposal.cs:19:33:19:34 | p1 |
-| Disposal.cs:19:44:19:45 | p2 |
-| Disposal.cs:19:69:19:70 | fs |
-| Disposal.cs:22:30:22:30 | d |
+| Disposal.cs:5:17:5:22 | field1 |
+| Disposal.cs:17:33:17:34 | p1 |
+| Disposal.cs:17:44:17:45 | p2 |
+| Disposal.cs:17:69:17:70 | fs |
+| Disposal.cs:20:30:20:30 | d |
diff --git a/csharp/ql/test/library-tests/commons/Disposal/options b/csharp/ql/test/library-tests/commons/Disposal/options
new file mode 100644
index 00000000000..3b212f77b23
--- /dev/null
+++ b/csharp/ql/test/library-tests/commons/Disposal/options
@@ -0,0 +1 @@
+semmle-extractor-options: --cil /r:System.Net.Http.dll /r:System.Runtime.Extensions.dll /r:System.Private.Xml.dll
diff --git a/csharp/ql/test/library-tests/commons/GeneratedCode/NonGeneratedCode.cs b/csharp/ql/test/library-tests/commons/GeneratedCode/NonGeneratedCode.cs
index 176272143a5..f80534c4120 100644
--- a/csharp/ql/test/library-tests/commons/GeneratedCode/NonGeneratedCode.cs
+++ b/csharp/ql/test/library-tests/commons/GeneratedCode/NonGeneratedCode.cs
@@ -1,5 +1,3 @@
using System;
class NonGeneratedCode { }
-
-// semmle-extractor-options: /r:System.Diagnostics.Tools.dll
diff --git a/csharp/ql/test/library-tests/commons/GeneratedCode/options b/csharp/ql/test/library-tests/commons/GeneratedCode/options
new file mode 100644
index 00000000000..9629de49425
--- /dev/null
+++ b/csharp/ql/test/library-tests/commons/GeneratedCode/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Diagnostics.Tools.dll
diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitMethods.cs b/csharp/ql/test/library-tests/controlflow/graph/ExitMethods.cs
index 3d821a1d335..a4d5bf1381f 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/ExitMethods.cs
+++ b/csharp/ql/test/library-tests/controlflow/graph/ExitMethods.cs
@@ -146,5 +146,3 @@ class ExitMethods
Console.WriteLine("dead");
}
}
-
-// semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Windows.cs ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs
diff --git a/csharp/ql/test/library-tests/controlflow/graph/cflow.cs b/csharp/ql/test/library-tests/controlflow/graph/cflow.cs
index f1b4a8a2e15..5bdb1a268b5 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/cflow.cs
+++ b/csharp/ql/test/library-tests/controlflow/graph/cflow.cs
@@ -300,5 +300,3 @@ class NegationInConstructor
new NegationInConstructor(i: 0, b: !(i > 0) && s != null, s: "");
}
}
-
-// semmle-extractor-options: /r:System.Linq.dll /r:System.Runtime.Extensions.dll
diff --git a/csharp/ql/test/library-tests/controlflow/graph/options b/csharp/ql/test/library-tests/controlflow/graph/options
new file mode 100644
index 00000000000..c4ecf28a152
--- /dev/null
+++ b/csharp/ql/test/library-tests/controlflow/graph/options
@@ -0,0 +1,2 @@
+semmle-extractor-options: /r:System.Linq.dll /r:System.Runtime.Extensions.dll
+semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Windows.cs ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs
diff --git a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected
index 2303633e4f4..6604ed7314e 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected
@@ -1,24 +1,24 @@
abstractValue
-| 0 | Collections.cs:12:32:12:32 | 0 |
-| 0 | Collections.cs:14:28:14:28 | 0 |
-| 0 | Collections.cs:16:27:16:27 | 0 |
-| 0 | Collections.cs:17:28:17:28 | 0 |
-| 0 | Collections.cs:23:31:23:31 | 0 |
-| 0 | Collections.cs:25:27:25:27 | 0 |
-| 0 | Collections.cs:27:26:27:26 | 0 |
-| 0 | Collections.cs:28:27:28:27 | 0 |
-| 0 | Collections.cs:34:33:34:33 | 0 |
-| 0 | Collections.cs:36:29:36:29 | 0 |
-| 0 | Collections.cs:38:28:38:28 | 0 |
-| 0 | Collections.cs:39:29:39:29 | 0 |
-| 0 | Collections.cs:50:27:50:27 | 0 |
-| 0 | Collections.cs:57:24:57:24 | 0 |
-| 0 | Collections.cs:65:24:65:24 | 0 |
-| 0 | Collections.cs:76:36:76:36 | 0 |
-| 0 | Collections.cs:78:36:78:36 | 0 |
-| 0 | Collections.cs:80:35:80:35 | 0 |
-| 0 | Collections.cs:81:36:81:36 | 0 |
-| 0 | Collections.cs:87:17:87:32 | 0 |
+| 0 | Collections.cs:11:32:11:32 | 0 |
+| 0 | Collections.cs:13:28:13:28 | 0 |
+| 0 | Collections.cs:15:27:15:27 | 0 |
+| 0 | Collections.cs:16:28:16:28 | 0 |
+| 0 | Collections.cs:22:31:22:31 | 0 |
+| 0 | Collections.cs:24:27:24:27 | 0 |
+| 0 | Collections.cs:26:26:26:26 | 0 |
+| 0 | Collections.cs:27:27:27:27 | 0 |
+| 0 | Collections.cs:33:33:33:33 | 0 |
+| 0 | Collections.cs:35:29:35:29 | 0 |
+| 0 | Collections.cs:37:28:37:28 | 0 |
+| 0 | Collections.cs:38:29:38:29 | 0 |
+| 0 | Collections.cs:49:27:49:27 | 0 |
+| 0 | Collections.cs:56:24:56:24 | 0 |
+| 0 | Collections.cs:64:24:64:24 | 0 |
+| 0 | Collections.cs:75:36:75:36 | 0 |
+| 0 | Collections.cs:77:36:77:36 | 0 |
+| 0 | Collections.cs:79:35:79:35 | 0 |
+| 0 | Collections.cs:80:36:80:36 | 0 |
+| 0 | Collections.cs:86:17:86:32 | 0 |
| 0 | Guards.cs:12:24:12:24 | 0 |
| 0 | Guards.cs:78:26:78:26 | 0 |
| 0 | Guards.cs:80:25:80:25 | 0 |
@@ -33,19 +33,19 @@ abstractValue
| 0 | Guards.cs:329:17:329:19 | access to constant A |
| 0 | Guards.cs:334:20:334:20 | 0 |
| 0 | Splitting.cs:137:20:137:20 | 0 |
-| 1 | Collections.cs:13:28:13:28 | 1 |
-| 1 | Collections.cs:15:28:15:28 | 1 |
-| 1 | Collections.cs:18:28:18:28 | 1 |
-| 1 | Collections.cs:24:27:24:27 | 1 |
-| 1 | Collections.cs:26:27:26:27 | 1 |
-| 1 | Collections.cs:29:27:29:27 | 1 |
-| 1 | Collections.cs:35:29:35:29 | 1 |
-| 1 | Collections.cs:37:29:37:29 | 1 |
-| 1 | Collections.cs:40:29:40:29 | 1 |
-| 1 | Collections.cs:77:36:77:36 | 1 |
-| 1 | Collections.cs:79:36:79:36 | 1 |
-| 1 | Collections.cs:82:36:82:36 | 1 |
-| 1 | Collections.cs:89:13:89:32 | 1 |
+| 1 | Collections.cs:12:28:12:28 | 1 |
+| 1 | Collections.cs:14:28:14:28 | 1 |
+| 1 | Collections.cs:17:28:17:28 | 1 |
+| 1 | Collections.cs:23:27:23:27 | 1 |
+| 1 | Collections.cs:25:27:25:27 | 1 |
+| 1 | Collections.cs:28:27:28:27 | 1 |
+| 1 | Collections.cs:34:29:34:29 | 1 |
+| 1 | Collections.cs:36:29:36:29 | 1 |
+| 1 | Collections.cs:39:29:39:29 | 1 |
+| 1 | Collections.cs:76:36:76:36 | 1 |
+| 1 | Collections.cs:78:36:78:36 | 1 |
+| 1 | Collections.cs:81:36:81:36 | 1 |
+| 1 | Collections.cs:88:13:88:32 | 1 |
| 1 | Guards.cs:92:25:92:25 | 1 |
| 1 | Guards.cs:243:17:243:17 | 1 |
| 1 | Guards.cs:246:18:246:18 | 1 |
@@ -59,19 +59,19 @@ abstractValue
| 1 | Guards.cs:331:17:331:19 | access to constant B |
| 1 | Guards.cs:334:13:334:15 | access to constant B |
| 1 | Guards.cs:335:18:335:18 | 1 |
-| 3 | Collections.cs:55:13:55:42 | 3 |
-| 3 | Collections.cs:63:17:63:46 | 3 |
+| 3 | Collections.cs:54:13:54:42 | 3 |
+| 3 | Collections.cs:62:17:62:46 | 3 |
| 10 | Guards.cs:84:25:84:26 | 10 |
| 10 | Guards.cs:86:26:86:27 | 10 |
-| empty | Collections.cs:54:13:54:16 | access to parameter args |
-| empty | Collections.cs:57:9:57:25 | ... = ... |
-| empty | Collections.cs:57:13:57:25 | array creation of type String[] |
-| empty | Collections.cs:58:9:58:13 | ... = ... |
-| empty | Collections.cs:58:13:58:13 | access to local variable x |
-| empty | Collections.cs:65:13:65:13 | access to local variable x |
-| empty | Collections.cs:87:17:87:32 | array creation of type String[] |
-| empty | Collections.cs:87:30:87:32 | { ..., ... } |
-| empty | Collections.cs:88:22:88:24 | { ..., ... } |
+| empty | Collections.cs:53:13:53:16 | access to parameter args |
+| empty | Collections.cs:56:9:56:25 | ... = ... |
+| empty | Collections.cs:56:13:56:25 | array creation of type String[] |
+| empty | Collections.cs:57:9:57:13 | ... = ... |
+| empty | Collections.cs:57:13:57:13 | access to local variable x |
+| empty | Collections.cs:64:13:64:13 | access to local variable x |
+| empty | Collections.cs:86:17:86:32 | array creation of type String[] |
+| empty | Collections.cs:86:30:86:32 | { ..., ... } |
+| empty | Collections.cs:87:22:87:24 | { ..., ... } |
| false | Assert.cs:85:61:85:65 | false |
| false | Guards.cs:178:16:178:20 | false |
| false | Guards.cs:181:53:181:57 | false |
@@ -79,18 +79,18 @@ abstractValue
| false | Guards.cs:228:18:228:22 | false |
| false | Guards.cs:295:18:295:22 | false |
| false | Guards.cs:305:18:305:22 | false |
-| non-empty | Collections.cs:55:9:55:42 | ... = ... |
-| non-empty | Collections.cs:55:13:55:42 | array creation of type String[] |
-| non-empty | Collections.cs:55:26:55:42 | { ..., ... } |
-| non-empty | Collections.cs:56:9:56:13 | ... = ... |
-| non-empty | Collections.cs:56:13:56:13 | access to local variable x |
-| non-empty | Collections.cs:63:17:63:46 | array creation of type String[] |
-| non-empty | Collections.cs:63:30:63:46 | { ..., ... } |
-| non-empty | Collections.cs:68:13:68:13 | access to local variable x |
-| non-empty | Collections.cs:89:9:89:32 | ... = ... |
-| non-empty | Collections.cs:89:13:89:32 | array creation of type String[] |
-| non-empty | Collections.cs:89:26:89:32 | { ..., ... } |
-| non-empty | Collections.cs:90:22:90:28 | { ..., ... } |
+| non-empty | Collections.cs:54:9:54:42 | ... = ... |
+| non-empty | Collections.cs:54:13:54:42 | array creation of type String[] |
+| non-empty | Collections.cs:54:26:54:42 | { ..., ... } |
+| non-empty | Collections.cs:55:9:55:13 | ... = ... |
+| non-empty | Collections.cs:55:13:55:13 | access to local variable x |
+| non-empty | Collections.cs:62:17:62:46 | array creation of type String[] |
+| non-empty | Collections.cs:62:30:62:46 | { ..., ... } |
+| non-empty | Collections.cs:67:13:67:13 | access to local variable x |
+| non-empty | Collections.cs:88:9:88:32 | ... = ... |
+| non-empty | Collections.cs:88:13:88:32 | array creation of type String[] |
+| non-empty | Collections.cs:88:26:88:32 | { ..., ... } |
+| non-empty | Collections.cs:89:22:89:28 | { ..., ... } |
| non-null | Assert.cs:9:31:9:32 | "" |
| non-null | Assert.cs:10:9:10:13 | access to type Debug |
| non-null | Assert.cs:11:9:11:15 | access to type Console |
@@ -126,68 +126,72 @@ abstractValue
| non-null | Assert.cs:80:9:80:14 | access to type Assert |
| non-null | Assert.cs:81:9:81:15 | access to type Console |
| non-null | Assert.cs:93:9:93:35 | this access |
-| non-null | Collections.cs:12:17:12:20 | access to parameter args |
+| non-null | Collections.cs:11:17:11:20 | access to parameter args |
+| non-null | Collections.cs:12:13:12:16 | access to parameter args |
| non-null | Collections.cs:13:13:13:16 | access to parameter args |
| non-null | Collections.cs:14:13:14:16 | access to parameter args |
| non-null | Collections.cs:15:13:15:16 | access to parameter args |
| non-null | Collections.cs:16:13:16:16 | access to parameter args |
| non-null | Collections.cs:17:13:17:16 | access to parameter args |
-| non-null | Collections.cs:18:13:18:16 | access to parameter args |
-| non-null | Collections.cs:23:17:23:20 | access to parameter args |
+| non-null | Collections.cs:22:17:22:20 | access to parameter args |
+| non-null | Collections.cs:23:13:23:16 | access to parameter args |
| non-null | Collections.cs:24:13:24:16 | access to parameter args |
| non-null | Collections.cs:25:13:25:16 | access to parameter args |
| non-null | Collections.cs:26:13:26:16 | access to parameter args |
| non-null | Collections.cs:27:13:27:16 | access to parameter args |
| non-null | Collections.cs:28:13:28:16 | access to parameter args |
-| non-null | Collections.cs:29:13:29:16 | access to parameter args |
-| non-null | Collections.cs:34:17:34:20 | access to parameter args |
+| non-null | Collections.cs:33:17:33:20 | access to parameter args |
+| non-null | Collections.cs:34:13:34:16 | access to parameter args |
| non-null | Collections.cs:35:13:35:16 | access to parameter args |
| non-null | Collections.cs:36:13:36:16 | access to parameter args |
| non-null | Collections.cs:37:13:37:16 | access to parameter args |
| non-null | Collections.cs:38:13:38:16 | access to parameter args |
| non-null | Collections.cs:39:13:39:16 | access to parameter args |
-| non-null | Collections.cs:40:13:40:16 | access to parameter args |
-| non-null | Collections.cs:45:17:45:20 | access to parameter args |
-| non-null | Collections.cs:50:13:50:16 | access to parameter args |
-| non-null | Collections.cs:52:17:52:20 | access to parameter args |
-| non-null | Collections.cs:52:17:52:30 | call to method ToArray |
-| non-null | Collections.cs:53:9:53:12 | access to parameter args |
+| non-null | Collections.cs:44:17:44:20 | access to parameter args |
+| non-null | Collections.cs:49:13:49:16 | access to parameter args |
+| non-null | Collections.cs:51:17:51:20 | access to parameter args |
+| non-null | Collections.cs:51:17:51:30 | call to method ToArray |
+| non-null | Collections.cs:52:9:52:12 | access to parameter args |
+| non-null | Collections.cs:53:9:53:9 | access to local variable x |
+| non-null | Collections.cs:53:9:53:26 | ... = ... |
+| non-null | Collections.cs:53:13:53:16 | access to parameter args |
+| non-null | Collections.cs:53:13:53:26 | call to method ToArray |
| non-null | Collections.cs:54:9:54:9 | access to local variable x |
-| non-null | Collections.cs:54:9:54:26 | ... = ... |
-| non-null | Collections.cs:54:13:54:16 | access to parameter args |
-| non-null | Collections.cs:54:13:54:26 | call to method ToArray |
+| non-null | Collections.cs:54:9:54:42 | ... = ... |
+| non-null | Collections.cs:54:13:54:42 | array creation of type String[] |
+| non-null | Collections.cs:54:28:54:30 | "a" |
+| non-null | Collections.cs:54:33:54:35 | "b" |
+| non-null | Collections.cs:54:38:54:40 | "c" |
| non-null | Collections.cs:55:9:55:9 | access to local variable x |
-| non-null | Collections.cs:55:9:55:42 | ... = ... |
-| non-null | Collections.cs:55:13:55:42 | array creation of type String[] |
-| non-null | Collections.cs:55:28:55:30 | "a" |
-| non-null | Collections.cs:55:33:55:35 | "b" |
-| non-null | Collections.cs:55:38:55:40 | "c" |
+| non-null | Collections.cs:55:9:55:13 | ... = ... |
+| non-null | Collections.cs:55:13:55:13 | access to local variable x |
| non-null | Collections.cs:56:9:56:9 | access to local variable x |
-| non-null | Collections.cs:56:9:56:13 | ... = ... |
-| non-null | Collections.cs:56:13:56:13 | access to local variable x |
+| non-null | Collections.cs:56:9:56:25 | ... = ... |
+| non-null | Collections.cs:56:13:56:25 | array creation of type String[] |
| non-null | Collections.cs:57:9:57:9 | access to local variable x |
-| non-null | Collections.cs:57:9:57:25 | ... = ... |
-| non-null | Collections.cs:57:13:57:25 | array creation of type String[] |
-| non-null | Collections.cs:58:9:58:9 | access to local variable x |
-| non-null | Collections.cs:58:9:58:13 | ... = ... |
-| non-null | Collections.cs:58:13:58:13 | access to local variable x |
-| non-null | Collections.cs:63:17:63:46 | array creation of type String[] |
-| non-null | Collections.cs:63:17:63:55 | call to method ToList |
-| non-null | Collections.cs:63:32:63:34 | "a" |
-| non-null | Collections.cs:63:37:63:39 | "b" |
-| non-null | Collections.cs:63:42:63:44 | "c" |
-| non-null | Collections.cs:64:9:64:9 | access to local variable x |
-| non-null | Collections.cs:65:13:65:13 | access to local variable x |
+| non-null | Collections.cs:57:9:57:13 | ... = ... |
+| non-null | Collections.cs:57:13:57:13 | access to local variable x |
+| non-null | Collections.cs:62:17:62:46 | array creation of type String[] |
+| non-null | Collections.cs:62:17:62:55 | call to method ToList |
+| non-null | Collections.cs:62:32:62:34 | "a" |
+| non-null | Collections.cs:62:37:62:39 | "b" |
+| non-null | Collections.cs:62:42:62:44 | "c" |
+| non-null | Collections.cs:63:9:63:9 | access to local variable x |
+| non-null | Collections.cs:64:13:64:13 | access to local variable x |
+| non-null | Collections.cs:66:13:66:13 | access to local variable x |
+| non-null | Collections.cs:66:19:66:21 | "a" |
| non-null | Collections.cs:67:13:67:13 | access to local variable x |
-| non-null | Collections.cs:67:19:67:21 | "a" |
-| non-null | Collections.cs:68:13:68:13 | access to local variable x |
-| non-null | Collections.cs:68:19:68:21 | "b" |
-| non-null | Collections.cs:74:35:74:35 | access to parameter s |
-| non-null | Collections.cs:74:40:74:41 | "" |
-| non-null | Collections.cs:75:17:75:20 | access to parameter args |
-| non-null | Collections.cs:75:26:75:32 | access to local function IsEmpty |
-| non-null | Collections.cs:75:26:75:32 | delegate creation of type Func |
-| non-null | Collections.cs:75:26:75:32 | this access |
+| non-null | Collections.cs:67:19:67:21 | "b" |
+| non-null | Collections.cs:73:35:73:35 | access to parameter s |
+| non-null | Collections.cs:73:40:73:41 | "" |
+| non-null | Collections.cs:74:17:74:20 | access to parameter args |
+| non-null | Collections.cs:74:26:74:32 | access to local function IsEmpty |
+| non-null | Collections.cs:74:26:74:32 | delegate creation of type Func |
+| non-null | Collections.cs:74:26:74:32 | this access |
+| non-null | Collections.cs:75:13:75:16 | access to parameter args |
+| non-null | Collections.cs:75:24:75:30 | access to local function IsEmpty |
+| non-null | Collections.cs:75:24:75:30 | delegate creation of type Func |
+| non-null | Collections.cs:75:24:75:30 | this access |
| non-null | Collections.cs:76:13:76:16 | access to parameter args |
| non-null | Collections.cs:76:24:76:30 | access to local function IsEmpty |
| non-null | Collections.cs:76:24:76:30 | delegate creation of type Func |
@@ -212,24 +216,20 @@ abstractValue
| non-null | Collections.cs:81:24:81:30 | access to local function IsEmpty |
| non-null | Collections.cs:81:24:81:30 | delegate creation of type Func |
| non-null | Collections.cs:81:24:81:30 | this access |
-| non-null | Collections.cs:82:13:82:16 | access to parameter args |
-| non-null | Collections.cs:82:24:82:30 | access to local function IsEmpty |
-| non-null | Collections.cs:82:24:82:30 | delegate creation of type Func |
-| non-null | Collections.cs:82:24:82:30 | this access |
-| non-null | Collections.cs:87:17:87:32 | array creation of type String[] |
-| non-null | Collections.cs:88:22:88:24 | array creation of type String[] |
-| non-null | Collections.cs:89:9:89:9 | access to local variable x |
-| non-null | Collections.cs:89:9:89:32 | ... = ... |
-| non-null | Collections.cs:89:13:89:32 | array creation of type String[] |
-| non-null | Collections.cs:89:28:89:30 | "a" |
-| non-null | Collections.cs:90:22:90:28 | array creation of type String[] |
-| non-null | Collections.cs:90:24:90:26 | "a" |
-| non-null | Collections.cs:95:29:95:32 | access to parameter args |
-| non-null | Collections.cs:96:13:96:19 | access to type Console |
-| non-null | Collections.cs:96:31:96:34 | access to parameter args |
-| non-null | Collections.cs:101:29:101:32 | access to parameter args |
-| non-null | Collections.cs:103:9:103:15 | access to type Console |
-| non-null | Collections.cs:103:27:103:30 | access to parameter args |
+| non-null | Collections.cs:86:17:86:32 | array creation of type String[] |
+| non-null | Collections.cs:87:22:87:24 | array creation of type String[] |
+| non-null | Collections.cs:88:9:88:9 | access to local variable x |
+| non-null | Collections.cs:88:9:88:32 | ... = ... |
+| non-null | Collections.cs:88:13:88:32 | array creation of type String[] |
+| non-null | Collections.cs:88:28:88:30 | "a" |
+| non-null | Collections.cs:89:22:89:28 | array creation of type String[] |
+| non-null | Collections.cs:89:24:89:26 | "a" |
+| non-null | Collections.cs:94:29:94:32 | access to parameter args |
+| non-null | Collections.cs:95:13:95:19 | access to type Console |
+| non-null | Collections.cs:95:31:95:34 | access to parameter args |
+| non-null | Collections.cs:100:29:100:32 | access to parameter args |
+| non-null | Collections.cs:102:9:102:15 | access to type Console |
+| non-null | Collections.cs:102:27:102:30 | access to parameter args |
| non-null | Guards.cs:12:13:12:13 | access to parameter s |
| non-null | Guards.cs:14:13:14:19 | access to type Console |
| non-null | Guards.cs:14:31:14:31 | access to parameter s |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/Assert.cs b/csharp/ql/test/library-tests/controlflow/guards/Assert.cs
index 77b2084963c..a353f669e4a 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/Assert.cs
+++ b/csharp/ql/test/library-tests/controlflow/guards/Assert.cs
@@ -94,5 +94,3 @@ class AssertTests
return b1 && !b2;
}
}
-
-// semmle-extractor-options: ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs
diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected
index 40d144f3719..67150b178dc 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected
@@ -13,11 +13,11 @@
| 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:94:16:94:17 | access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | true |
| Assert.cs:94:23:94:24 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | false |
-| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
-| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
+| Collections.cs:51:17:51:20 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:52:9:52:12 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:53:13:53:16 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:66:13:66:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
+| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
| 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: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 |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs
index 49611765d16..036b2531771 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs
+++ b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs
@@ -1,4 +1,3 @@
-// semmle-extractor-options: /r:System.Collections.Specialized.dll /r:System.Collections.dll /r:System.Linq.dll
using System;
using System.Collections;
using System.Collections.Generic;
@@ -103,4 +102,3 @@ public class Collections
Console.WriteLine(args);
}
}
-
diff --git a/csharp/ql/test/library-tests/controlflow/guards/Collections.expected b/csharp/ql/test/library-tests/controlflow/guards/Collections.expected
index 1d08bcce512..dcc4148a667 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/Collections.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/Collections.expected
@@ -1,37 +1,37 @@
-| Collections.cs:12:17:12:32 | ... == ... | Collections.cs:12:17:12:20 | access to parameter args | false | false |
-| Collections.cs:12:17:12:32 | ... == ... | Collections.cs:12:17:12:20 | access to parameter args | true | true |
-| Collections.cs:13:13:13:28 | ... == ... | Collections.cs:13:13:13:16 | access to parameter args | true | false |
-| Collections.cs:14:13:14:28 | ... != ... | Collections.cs:14:13:14:16 | access to parameter args | false | true |
-| Collections.cs:14:13:14:28 | ... != ... | Collections.cs:14:13:14:16 | access to parameter args | true | false |
-| Collections.cs:15:13:15:28 | ... != ... | Collections.cs:15:13:15:16 | access to parameter args | false | false |
-| Collections.cs:16:13:16:27 | ... > ... | Collections.cs:16:13:16:16 | access to parameter args | true | false |
-| Collections.cs:18:13:18:28 | ... >= ... | Collections.cs:18:13:18:16 | access to parameter args | true | false |
-| Collections.cs:23:17:23:31 | ... == ... | Collections.cs:23:17:23:20 | access to parameter args | false | false |
-| Collections.cs:23:17:23:31 | ... == ... | Collections.cs:23:17:23:20 | access to parameter args | true | true |
-| Collections.cs:24:13:24:27 | ... == ... | Collections.cs:24:13:24:16 | access to parameter args | true | false |
-| Collections.cs:25:13:25:27 | ... != ... | Collections.cs:25:13:25:16 | access to parameter args | false | true |
-| Collections.cs:25:13:25:27 | ... != ... | Collections.cs:25:13:25:16 | access to parameter args | true | false |
-| Collections.cs:26:13:26:27 | ... != ... | Collections.cs:26:13:26:16 | access to parameter args | false | false |
-| Collections.cs:27:13:27:26 | ... > ... | Collections.cs:27:13:27:16 | access to parameter args | true | false |
-| Collections.cs:29:13:29:27 | ... >= ... | Collections.cs:29:13:29:16 | access to parameter args | true | false |
-| Collections.cs:34:17:34:33 | ... == ... | Collections.cs:34:17:34:20 | access to parameter args | false | false |
-| Collections.cs:34:17:34:33 | ... == ... | Collections.cs:34:17:34:20 | access to parameter args | true | true |
-| Collections.cs:35:13:35:29 | ... == ... | Collections.cs:35:13:35:16 | access to parameter args | true | false |
-| Collections.cs:36:13:36:29 | ... != ... | Collections.cs:36:13:36:16 | access to parameter args | false | true |
-| Collections.cs:36:13:36:29 | ... != ... | Collections.cs:36:13:36:16 | access to parameter args | true | false |
-| Collections.cs:37:13:37:29 | ... != ... | Collections.cs:37:13:37:16 | access to parameter args | false | false |
-| Collections.cs:38:13:38:28 | ... > ... | Collections.cs:38:13:38:16 | access to parameter args | true | false |
-| Collections.cs:40:13:40:29 | ... >= ... | Collections.cs:40:13:40:16 | access to parameter args | true | false |
-| Collections.cs:45:17:45:26 | call to method Any | Collections.cs:45:17:45:20 | access to parameter args | false | true |
-| Collections.cs:45:17:45:26 | call to method Any | Collections.cs:45:17:45:20 | access to parameter args | true | false |
-| Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | false |
-| Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | true | true |
-| Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | false | false |
-| Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | true |
-| Collections.cs:75:17:75:33 | call to method Any | Collections.cs:75:17:75:20 | access to parameter args | true | false |
-| Collections.cs:76:13:76:36 | ... == ... | Collections.cs:76:13:76:16 | access to parameter args | false | false |
-| Collections.cs:77:13:77:36 | ... == ... | Collections.cs:77:13:77:16 | access to parameter args | true | false |
-| Collections.cs:78:13:78:36 | ... != ... | Collections.cs:78:13:78:16 | access to parameter args | true | false |
-| Collections.cs:79:13:79:36 | ... != ... | Collections.cs:79:13:79:16 | access to parameter args | false | false |
-| Collections.cs:80:13:80:35 | ... > ... | Collections.cs:80:13:80:16 | access to parameter args | true | false |
-| Collections.cs:82:13:82:36 | ... >= ... | Collections.cs:82:13:82:16 | access to parameter args | true | false |
+| Collections.cs:11:17:11:32 | ... == ... | Collections.cs:11:17:11:20 | access to parameter args | false | false |
+| Collections.cs:11:17:11:32 | ... == ... | Collections.cs:11:17:11:20 | access to parameter args | true | true |
+| Collections.cs:12:13:12:28 | ... == ... | Collections.cs:12:13:12:16 | access to parameter args | true | false |
+| Collections.cs:13:13:13:28 | ... != ... | Collections.cs:13:13:13:16 | access to parameter args | false | true |
+| Collections.cs:13:13:13:28 | ... != ... | Collections.cs:13:13:13:16 | access to parameter args | true | false |
+| Collections.cs:14:13:14:28 | ... != ... | Collections.cs:14:13:14:16 | access to parameter args | false | false |
+| Collections.cs:15:13:15:27 | ... > ... | Collections.cs:15:13:15:16 | access to parameter args | true | false |
+| Collections.cs:17:13:17:28 | ... >= ... | Collections.cs:17:13:17:16 | access to parameter args | true | false |
+| Collections.cs:22:17:22:31 | ... == ... | Collections.cs:22:17:22:20 | access to parameter args | false | false |
+| Collections.cs:22:17:22:31 | ... == ... | Collections.cs:22:17:22:20 | access to parameter args | true | true |
+| Collections.cs:23:13:23:27 | ... == ... | Collections.cs:23:13:23:16 | access to parameter args | true | false |
+| Collections.cs:24:13:24:27 | ... != ... | Collections.cs:24:13:24:16 | access to parameter args | false | true |
+| Collections.cs:24:13:24:27 | ... != ... | Collections.cs:24:13:24:16 | access to parameter args | true | false |
+| Collections.cs:25:13:25:27 | ... != ... | Collections.cs:25:13:25:16 | access to parameter args | false | false |
+| Collections.cs:26:13:26:26 | ... > ... | Collections.cs:26:13:26:16 | access to parameter args | true | false |
+| Collections.cs:28:13:28:27 | ... >= ... | Collections.cs:28:13:28:16 | access to parameter args | true | false |
+| Collections.cs:33:17:33:33 | ... == ... | Collections.cs:33:17:33:20 | access to parameter args | false | false |
+| Collections.cs:33:17:33:33 | ... == ... | Collections.cs:33:17:33:20 | access to parameter args | true | true |
+| Collections.cs:34:13:34:29 | ... == ... | Collections.cs:34:13:34:16 | access to parameter args | true | false |
+| Collections.cs:35:13:35:29 | ... != ... | Collections.cs:35:13:35:16 | access to parameter args | false | true |
+| Collections.cs:35:13:35:29 | ... != ... | Collections.cs:35:13:35:16 | access to parameter args | true | false |
+| Collections.cs:36:13:36:29 | ... != ... | Collections.cs:36:13:36:16 | access to parameter args | false | false |
+| Collections.cs:37:13:37:28 | ... > ... | Collections.cs:37:13:37:16 | access to parameter args | true | false |
+| Collections.cs:39:13:39:29 | ... >= ... | Collections.cs:39:13:39:16 | access to parameter args | true | false |
+| Collections.cs:44:17:44:26 | call to method Any | Collections.cs:44:17:44:20 | access to parameter args | false | true |
+| Collections.cs:44:17:44:26 | call to method Any | Collections.cs:44:17:44:20 | access to parameter args | true | false |
+| Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false | false |
+| Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | true | true |
+| Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | false | false |
+| Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true | true |
+| Collections.cs:74:17:74:33 | call to method Any | Collections.cs:74:17:74:20 | access to parameter args | true | false |
+| Collections.cs:75:13:75:36 | ... == ... | Collections.cs:75:13:75:16 | access to parameter args | false | false |
+| Collections.cs:76:13:76:36 | ... == ... | Collections.cs:76:13:76:16 | access to parameter args | true | false |
+| Collections.cs:77:13:77:36 | ... != ... | Collections.cs:77:13:77:16 | access to parameter args | true | false |
+| Collections.cs:78:13:78:36 | ... != ... | Collections.cs:78:13:78:16 | access to parameter args | false | false |
+| Collections.cs:79:13:79:35 | ... > ... | Collections.cs:79:13:79:16 | access to parameter args | true | false |
+| Collections.cs:81:13:81:36 | ... >= ... | Collections.cs:81:13:81:16 | access to parameter args | true | false |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/ExtractorOptions.cs b/csharp/ql/test/library-tests/controlflow/guards/ExtractorOptions.cs
index 3353234761a..7dc5c58110b 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/ExtractorOptions.cs
+++ b/csharp/ql/test/library-tests/controlflow/guards/ExtractorOptions.cs
@@ -1,2 +1 @@
-// semmle-extractor-options: --cil
#nullable enable
diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected
index 404c0197556..24e8afd2278 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected
@@ -44,14 +44,14 @@
| Assert.cs:93:33:93:34 | [assertion success, b1 (line 91): true] access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | false |
| Assert.cs:94:16:94:17 | [b1 (line 91): true] access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | true |
| Assert.cs:94:23:94:24 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | false |
-| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
-| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty |
-| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
-| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
-| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty |
+| Collections.cs:51:17:51:20 | access to parameter args | Collections.cs:49:13:49:16 | access to parameter args | Collections.cs:49:13:49:16 | access to parameter args | non-empty |
+| Collections.cs:51:17:51:20 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:52:9:52:12 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:53:13:53:16 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:66:13:66:13 | access to local variable x | Collections.cs:64:13:64:13 | access to local variable x | Collections.cs:64:13:64:13 | access to local variable x | empty |
+| Collections.cs:66:13:66:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
+| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
+| Collections.cs:95:31:95:34 | access to parameter args | Collections.cs:94:29:94:32 | access to parameter args | Collections.cs:94:29:94:32 | access to parameter args | non-empty |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected
index bd5e3dbf1a1..ef82e7283a1 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected
@@ -28,14 +28,14 @@
| 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:94:16:94:17 | access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | Assert.cs:93:25:93:26 | access to parameter b1 | true |
| Assert.cs:94:23:94:24 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | Assert.cs:93:29:93:30 | access to parameter b2 | false |
-| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
-| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
-| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty |
-| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
-| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
-| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty |
+| Collections.cs:51:17:51:20 | access to parameter args | Collections.cs:49:13:49:16 | access to parameter args | Collections.cs:49:13:49:16 | access to parameter args | non-empty |
+| Collections.cs:51:17:51:20 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:52:9:52:12 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:53:13:53:16 | access to parameter args | Collections.cs:49:13:49:27 | ... == ... | Collections.cs:49:13:49:16 | access to parameter args | false |
+| Collections.cs:66:13:66:13 | access to local variable x | Collections.cs:64:13:64:13 | access to local variable x | Collections.cs:64:13:64:13 | access to local variable x | empty |
+| Collections.cs:66:13:66:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
+| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:64:13:64:24 | ... == ... | Collections.cs:64:13:64:13 | access to local variable x | true |
+| Collections.cs:95:31:95:34 | access to parameter args | Collections.cs:94:29:94:32 | access to parameter args | Collections.cs:94:29:94:32 | access to parameter args | non-empty |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs
index 67c8a4e78c8..045967d6134 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs
+++ b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs
@@ -349,4 +349,3 @@ public class Guards
o.ToString(); // null guarded
}
}
-
diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected
index ee5a0bb7017..45e70ce5531 100644
--- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected
+++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected
@@ -160,63 +160,63 @@
| Assert.cs:94:16:94:24 | ... && ... | true | Assert.cs:94:22:94:24 | !... | true |
| Assert.cs:94:22:94:24 | !... | false | Assert.cs:94:23:94:24 | access to parameter b2 | true |
| Assert.cs:94:22:94:24 | !... | true | Assert.cs:94:23:94:24 | access to parameter b2 | false |
-| Collections.cs:12:17:12:32 | ... == ... | false | Collections.cs:12:17:12:20 | access to parameter args | non-empty |
-| Collections.cs:12:17:12:32 | ... == ... | true | Collections.cs:12:17:12:20 | access to parameter args | empty |
-| Collections.cs:13:13:13:28 | ... == ... | true | Collections.cs:13:13:13:16 | access to parameter args | non-empty |
-| Collections.cs:14:13:14:28 | ... != ... | false | Collections.cs:14:13:14:16 | access to parameter args | empty |
-| Collections.cs:14:13:14:28 | ... != ... | true | Collections.cs:14:13:14:16 | access to parameter args | non-empty |
-| Collections.cs:15:13:15:28 | ... != ... | false | Collections.cs:15:13:15:16 | access to parameter args | non-empty |
-| Collections.cs:16:13:16:27 | ... > ... | true | Collections.cs:16:13:16:16 | access to parameter args | non-empty |
-| Collections.cs:18:13:18:28 | ... >= ... | true | Collections.cs:18:13:18:16 | access to parameter args | non-empty |
-| Collections.cs:23:17:23:31 | ... == ... | false | Collections.cs:23:17:23:20 | access to parameter args | non-empty |
-| Collections.cs:23:17:23:31 | ... == ... | true | Collections.cs:23:17:23:20 | access to parameter args | empty |
-| Collections.cs:24:13:24:27 | ... == ... | true | Collections.cs:24:13:24:16 | access to parameter args | non-empty |
-| Collections.cs:25:13:25:27 | ... != ... | false | Collections.cs:25:13:25:16 | access to parameter args | empty |
-| Collections.cs:25:13:25:27 | ... != ... | true | Collections.cs:25:13:25:16 | access to parameter args | non-empty |
-| Collections.cs:26:13:26:27 | ... != ... | false | Collections.cs:26:13:26:16 | access to parameter args | non-empty |
-| Collections.cs:27:13:27:26 | ... > ... | true | Collections.cs:27:13:27:16 | access to parameter args | non-empty |
-| Collections.cs:29:13:29:27 | ... >= ... | true | Collections.cs:29:13:29:16 | access to parameter args | non-empty |
-| Collections.cs:34:17:34:33 | ... == ... | false | Collections.cs:34:17:34:20 | access to parameter args | non-empty |
-| Collections.cs:34:17:34:33 | ... == ... | true | Collections.cs:34:17:34:20 | access to parameter args | empty |
-| Collections.cs:35:13:35:29 | ... == ... | true | Collections.cs:35:13:35:16 | access to parameter args | non-empty |
-| Collections.cs:36:13:36:29 | ... != ... | false | Collections.cs:36:13:36:16 | access to parameter args | empty |
-| Collections.cs:36:13:36:29 | ... != ... | true | Collections.cs:36:13:36:16 | access to parameter args | non-empty |
-| Collections.cs:37:13:37:29 | ... != ... | false | Collections.cs:37:13:37:16 | access to parameter args | non-empty |
-| Collections.cs:38:13:38:28 | ... > ... | true | Collections.cs:38:13:38:16 | access to parameter args | non-empty |
-| Collections.cs:40:13:40:29 | ... >= ... | true | Collections.cs:40:13:40:16 | access to parameter args | non-empty |
-| Collections.cs:45:17:45:26 | call to method Any | false | Collections.cs:45:17:45:20 | access to parameter args | empty |
-| Collections.cs:45:17:45:26 | call to method Any | true | Collections.cs:45:17:45:20 | access to parameter args | non-empty |
-| Collections.cs:50:13:50:27 | ... == ... | false | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
-| Collections.cs:50:13:50:27 | ... == ... | true | Collections.cs:50:13:50:16 | access to parameter args | empty |
-| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:42 | array creation of type String[] | empty |
-| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:42 | array creation of type String[] | non-empty |
-| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:42 | array creation of type String[] | non-null |
-| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:42 | array creation of type String[] | null |
-| Collections.cs:58:13:58:13 | access to local variable x | empty | Collections.cs:57:13:57:25 | array creation of type String[] | empty |
-| Collections.cs:58:13:58:13 | access to local variable x | non-empty | Collections.cs:57:13:57:25 | array creation of type String[] | non-empty |
-| Collections.cs:58:13:58:13 | access to local variable x | non-null | Collections.cs:57:13:57:25 | array creation of type String[] | non-null |
-| Collections.cs:58:13:58:13 | access to local variable x | null | Collections.cs:57:13:57:25 | array creation of type String[] | null |
-| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:55 | call to method ToList | empty |
-| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:55 | call to method ToList | non-empty |
-| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null |
-| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null |
-| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null |
-| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null |
-| Collections.cs:65:13:65:24 | ... == ... | false | Collections.cs:65:13:65:13 | access to local variable x | non-empty |
-| Collections.cs:65:13:65:24 | ... == ... | true | Collections.cs:65:13:65:13 | access to local variable x | empty |
-| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null |
-| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null |
-| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null |
-| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null |
-| Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:35:74:35 | access to parameter s | non-null |
-| Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:40:74:41 | "" | non-null |
-| Collections.cs:75:17:75:33 | call to method Any | true | Collections.cs:75:17:75:20 | access to parameter args | non-empty |
-| Collections.cs:76:13:76:36 | ... == ... | false | Collections.cs:76:13:76:16 | access to parameter args | non-empty |
-| Collections.cs:77:13:77:36 | ... == ... | true | Collections.cs:77:13:77:16 | access to parameter args | non-empty |
-| Collections.cs:78:13:78:36 | ... != ... | true | Collections.cs:78:13:78:16 | access to parameter args | non-empty |
-| Collections.cs:79:13:79:36 | ... != ... | false | Collections.cs:79:13:79:16 | access to parameter args | non-empty |
-| Collections.cs:80:13:80:35 | ... > ... | true | Collections.cs:80:13:80:16 | access to parameter args | non-empty |
-| Collections.cs:82:13:82:36 | ... >= ... | true | Collections.cs:82:13:82:16 | access to parameter args | non-empty |
+| Collections.cs:11:17:11:32 | ... == ... | false | Collections.cs:11:17:11:20 | access to parameter args | non-empty |
+| Collections.cs:11:17:11:32 | ... == ... | true | Collections.cs:11:17:11:20 | access to parameter args | empty |
+| Collections.cs:12:13:12:28 | ... == ... | true | Collections.cs:12:13:12:16 | access to parameter args | non-empty |
+| Collections.cs:13:13:13:28 | ... != ... | false | Collections.cs:13:13:13:16 | access to parameter args | empty |
+| Collections.cs:13:13:13:28 | ... != ... | true | Collections.cs:13:13:13:16 | access to parameter args | non-empty |
+| Collections.cs:14:13:14:28 | ... != ... | false | Collections.cs:14:13:14:16 | access to parameter args | non-empty |
+| Collections.cs:15:13:15:27 | ... > ... | true | Collections.cs:15:13:15:16 | access to parameter args | non-empty |
+| Collections.cs:17:13:17:28 | ... >= ... | true | Collections.cs:17:13:17:16 | access to parameter args | non-empty |
+| Collections.cs:22:17:22:31 | ... == ... | false | Collections.cs:22:17:22:20 | access to parameter args | non-empty |
+| Collections.cs:22:17:22:31 | ... == ... | true | Collections.cs:22:17:22:20 | access to parameter args | empty |
+| Collections.cs:23:13:23:27 | ... == ... | true | Collections.cs:23:13:23:16 | access to parameter args | non-empty |
+| Collections.cs:24:13:24:27 | ... != ... | false | Collections.cs:24:13:24:16 | access to parameter args | empty |
+| Collections.cs:24:13:24:27 | ... != ... | true | Collections.cs:24:13:24:16 | access to parameter args | non-empty |
+| Collections.cs:25:13:25:27 | ... != ... | false | Collections.cs:25:13:25:16 | access to parameter args | non-empty |
+| Collections.cs:26:13:26:26 | ... > ... | true | Collections.cs:26:13:26:16 | access to parameter args | non-empty |
+| Collections.cs:28:13:28:27 | ... >= ... | true | Collections.cs:28:13:28:16 | access to parameter args | non-empty |
+| Collections.cs:33:17:33:33 | ... == ... | false | Collections.cs:33:17:33:20 | access to parameter args | non-empty |
+| Collections.cs:33:17:33:33 | ... == ... | true | Collections.cs:33:17:33:20 | access to parameter args | empty |
+| Collections.cs:34:13:34:29 | ... == ... | true | Collections.cs:34:13:34:16 | access to parameter args | non-empty |
+| Collections.cs:35:13:35:29 | ... != ... | false | Collections.cs:35:13:35:16 | access to parameter args | empty |
+| Collections.cs:35:13:35:29 | ... != ... | true | Collections.cs:35:13:35:16 | access to parameter args | non-empty |
+| Collections.cs:36:13:36:29 | ... != ... | false | Collections.cs:36:13:36:16 | access to parameter args | non-empty |
+| Collections.cs:37:13:37:28 | ... > ... | true | Collections.cs:37:13:37:16 | access to parameter args | non-empty |
+| Collections.cs:39:13:39:29 | ... >= ... | true | Collections.cs:39:13:39:16 | access to parameter args | non-empty |
+| Collections.cs:44:17:44:26 | call to method Any | false | Collections.cs:44:17:44:20 | access to parameter args | empty |
+| Collections.cs:44:17:44:26 | call to method Any | true | Collections.cs:44:17:44:20 | access to parameter args | non-empty |
+| Collections.cs:49:13:49:27 | ... == ... | false | Collections.cs:49:13:49:16 | access to parameter args | non-empty |
+| Collections.cs:49:13:49:27 | ... == ... | true | Collections.cs:49:13:49:16 | access to parameter args | empty |
+| Collections.cs:55:13:55:13 | access to local variable x | empty | Collections.cs:54:13:54:42 | array creation of type String[] | empty |
+| Collections.cs:55:13:55:13 | access to local variable x | non-empty | Collections.cs:54:13:54:42 | array creation of type String[] | non-empty |
+| Collections.cs:55:13:55:13 | access to local variable x | non-null | Collections.cs:54:13:54:42 | array creation of type String[] | non-null |
+| Collections.cs:55:13:55:13 | access to local variable x | null | Collections.cs:54:13:54:42 | array creation of type String[] | null |
+| Collections.cs:57:13:57:13 | access to local variable x | empty | Collections.cs:56:13:56:25 | array creation of type String[] | empty |
+| Collections.cs:57:13:57:13 | access to local variable x | non-empty | Collections.cs:56:13:56:25 | array creation of type String[] | non-empty |
+| Collections.cs:57:13:57:13 | access to local variable x | non-null | Collections.cs:56:13:56:25 | array creation of type String[] | non-null |
+| Collections.cs:57:13:57:13 | access to local variable x | null | Collections.cs:56:13:56:25 | array creation of type String[] | null |
+| Collections.cs:63:9:63:9 | access to local variable x | empty | Collections.cs:62:17:62:55 | call to method ToList | empty |
+| Collections.cs:63:9:63:9 | access to local variable x | non-empty | Collections.cs:62:17:62:55 | call to method ToList | non-empty |
+| Collections.cs:63:9:63:9 | access to local variable x | non-null | Collections.cs:62:17:62:55 | call to method ToList | non-null |
+| Collections.cs:63:9:63:9 | access to local variable x | null | Collections.cs:62:17:62:55 | call to method ToList | null |
+| Collections.cs:64:13:64:13 | access to local variable x | non-null | Collections.cs:62:17:62:55 | call to method ToList | non-null |
+| Collections.cs:64:13:64:13 | access to local variable x | null | Collections.cs:62:17:62:55 | call to method ToList | null |
+| Collections.cs:64:13:64:24 | ... == ... | false | Collections.cs:64:13:64:13 | access to local variable x | non-empty |
+| Collections.cs:64:13:64:24 | ... == ... | true | Collections.cs:64:13:64:13 | access to local variable x | empty |
+| Collections.cs:66:13:66:13 | access to local variable x | non-null | Collections.cs:62:17:62:55 | call to method ToList | non-null |
+| Collections.cs:66:13:66:13 | access to local variable x | null | Collections.cs:62:17:62:55 | call to method ToList | null |
+| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:62:17:62:55 | call to method ToList | non-null |
+| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:62:17:62:55 | call to method ToList | null |
+| Collections.cs:73:35:73:41 | ... == ... | true | Collections.cs:73:35:73:35 | access to parameter s | non-null |
+| Collections.cs:73:35:73:41 | ... == ... | true | Collections.cs:73:40:73:41 | "" | non-null |
+| Collections.cs:74:17:74:33 | call to method Any | true | Collections.cs:74:17:74:20 | access to parameter args | non-empty |
+| Collections.cs:75:13:75:36 | ... == ... | false | Collections.cs:75:13:75:16 | access to parameter args | non-empty |
+| Collections.cs:76:13:76:36 | ... == ... | true | Collections.cs:76:13:76:16 | access to parameter args | non-empty |
+| Collections.cs:77:13:77:36 | ... != ... | true | Collections.cs:77:13:77:16 | access to parameter args | non-empty |
+| Collections.cs:78:13:78:36 | ... != ... | false | Collections.cs:78:13:78:16 | access to parameter args | non-empty |
+| Collections.cs:79:13:79:35 | ... > ... | true | Collections.cs:79:13:79:16 | access to parameter args | non-empty |
+| Collections.cs:81:13:81:36 | ... >= ... | true | Collections.cs:81:13:81:16 | access to parameter args | non-empty |
| Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true |
| Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false |
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:16:10:24 | ... == ... | true |
diff --git a/csharp/ql/test/library-tests/controlflow/guards/options b/csharp/ql/test/library-tests/controlflow/guards/options
new file mode 100644
index 00000000000..85a6cc13696
--- /dev/null
+++ b/csharp/ql/test/library-tests/controlflow/guards/options
@@ -0,0 +1,3 @@
+semmle-extractor-options: --cil
+semmle-extractor-options: ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs
+semmle-extractor-options: /r:System.Collections.Specialized.dll /r:System.Collections.dll /r:System.Linq.dll
diff --git a/csharp/ql/test/library-tests/conversion/boxing/Boxing.cs b/csharp/ql/test/library-tests/conversion/boxing/Boxing.cs
index b6c7eec0f97..a37d39aa2a0 100644
--- a/csharp/ql/test/library-tests/conversion/boxing/Boxing.cs
+++ b/csharp/ql/test/library-tests/conversion/boxing/Boxing.cs
@@ -45,5 +45,3 @@ class C
x1 = x15; // not a boxing conversion
}
}
-
-// semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/conversion/boxing/options b/csharp/ql/test/library-tests/conversion/boxing/options
new file mode 100644
index 00000000000..b136d9ed120
--- /dev/null
+++ b/csharp/ql/test/library-tests/conversion/boxing/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/conversion/identity/Identity.cs b/csharp/ql/test/library-tests/conversion/identity/Identity.cs
index 4a4fc6255c7..f79c8e26940 100644
--- a/csharp/ql/test/library-tests/conversion/identity/Identity.cs
+++ b/csharp/ql/test/library-tests/conversion/identity/Identity.cs
@@ -28,5 +28,3 @@ class C
x10 = x9;
}
}
-
-// semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/conversion/identity/options b/csharp/ql/test/library-tests/conversion/identity/options
new file mode 100644
index 00000000000..b136d9ed120
--- /dev/null
+++ b/csharp/ql/test/library-tests/conversion/identity/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.cs b/csharp/ql/test/library-tests/conversion/reftype/RefType.cs
index 04d74108387..152eb1dcd68 100644
--- a/csharp/ql/test/library-tests/conversion/reftype/RefType.cs
+++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.cs
@@ -91,5 +91,3 @@ class C3 where T5 : C1
{
public I4 M(I4 x) => x;
}
-
-// semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/conversion/reftype/options b/csharp/ql/test/library-tests/conversion/reftype/options
new file mode 100644
index 00000000000..b136d9ed120
--- /dev/null
+++ b/csharp/ql/test/library-tests/conversion/reftype/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll
diff --git a/csharp/ql/test/library-tests/csharp6/csharp6.cs b/csharp/ql/test/library-tests/csharp6/csharp6.cs
index ec349106e95..5414e1a5ee5 100644
--- a/csharp/ql/test/library-tests/csharp6/csharp6.cs
+++ b/csharp/ql/test/library-tests/csharp6/csharp6.cs
@@ -1,4 +1,4 @@
-/*
+/*
Testcase covering C# 6.0 features
*/
@@ -79,5 +79,3 @@ class IndexInitializers
};
}
}
-
-// semmle-extractor-options: /r:System.Linq.dll /langerversion:6.0
diff --git a/csharp/ql/test/library-tests/csharp6/options b/csharp/ql/test/library-tests/csharp6/options
new file mode 100644
index 00000000000..7cdcd240b4c
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp6/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Linq.dll /langerversion:6.0
diff --git a/csharp/ql/test/library-tests/csharp7.1/DefaultLiterals.expected b/csharp/ql/test/library-tests/csharp7.1/DefaultLiterals.expected
index 2d1b2aa51c0..68ebdab0711 100644
--- a/csharp/ql/test/library-tests/csharp7.1/DefaultLiterals.expected
+++ b/csharp/ql/test/library-tests/csharp7.1/DefaultLiterals.expected
@@ -1,7 +1,7 @@
-| csharp71.cs:7:17:7:23 | default | 0 |
-| csharp71.cs:7:30:7:41 | default(...) | 0 |
-| csharp71.cs:8:18:8:24 | default | 0 |
-| csharp71.cs:14:13:14:19 | default | 0 |
-| csharp71.cs:15:20:15:26 | default | null |
-| csharp71.cs:16:18:16:24 | default | false |
-| csharp71.cs:17:20:17:26 | default | 0 |
+| csharp71.cs:5:17:5:23 | default | 0 |
+| csharp71.cs:5:30:5:41 | default(...) | 0 |
+| csharp71.cs:6:18:6:24 | default | 0 |
+| csharp71.cs:12:13:12:19 | default | 0 |
+| csharp71.cs:13:20:13:26 | default | null |
+| csharp71.cs:14:18:14:24 | default | false |
+| csharp71.cs:15:20:15:26 | default | 0 |
diff --git a/csharp/ql/test/library-tests/csharp7.1/IsConstants.expected b/csharp/ql/test/library-tests/csharp7.1/IsConstants.expected
index 310a22189e2..ba321d96630 100644
--- a/csharp/ql/test/library-tests/csharp7.1/IsConstants.expected
+++ b/csharp/ql/test/library-tests/csharp7.1/IsConstants.expected
@@ -1,3 +1,3 @@
-| csharp71.cs:26:13:26:33 | ... is ... | csharp71.cs:26:13:26:24 | object creation of type Object | csharp71.cs:26:29:26:33 | "abc" | abc |
-| csharp71.cs:27:13:27:22 | ... is ... | csharp71.cs:27:13:27:14 | "" | csharp71.cs:27:19:27:22 | null | null |
-| csharp71.cs:28:13:28:21 | ... is ... | csharp71.cs:28:13:28:13 | access to local variable b | csharp71.cs:28:18:28:21 | true | true |
+| csharp71.cs:24:13:24:33 | ... is ... | csharp71.cs:24:13:24:24 | object creation of type Object | csharp71.cs:24:29:24:33 | "abc" | abc |
+| csharp71.cs:25:13:25:22 | ... is ... | csharp71.cs:25:13:25:14 | "" | csharp71.cs:25:19:25:22 | null | null |
+| csharp71.cs:26:13:26:21 | ... is ... | csharp71.cs:26:13:26:13 | access to local variable b | csharp71.cs:26:18:26:21 | true | true |
diff --git a/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected
index 35cf8a753a1..da9906904d4 100644
--- a/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected
@@ -1,77 +1,77 @@
csharp71.cs:
-# 3| [Class] DefaultLiterals
-# 5| 5: [Method] f
-# 5| -1: [TypeMention] Void
-# 6| 4: [BlockStmt] {...}
-# 7| 0: [LocalVariableDeclStmt] ... ...;
-# 7| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
-# 7| -1: [TypeMention] int
-# 7| 0: [LocalVariableAccess] access to local variable x
-# 7| 1: [CastExpr] (...) ...
-# 7| 1: [DefaultValueExpr] default
-# 7| 1: [LocalVariableDeclAndInitExpr] Int32 y = ...
-# 7| -1: [TypeMention] int
-# 7| 0: [LocalVariableAccess] access to local variable y
-# 7| 1: [DefaultValueExpr] default(...)
-# 7| 0: [TypeAccess] access to type Int32
-# 7| 0: [TypeMention] int
-# 8| 1: [IfStmt] if (...) ...
-# 8| 0: [EQExpr] ... == ...
-# 8| 0: [LocalVariableAccess] access to local variable x
-# 8| 1: [CastExpr] (...) ...
-# 8| 1: [DefaultValueExpr] default
-# 9| 1: [EmptyStmt] ;
-# 10| 2: [SwitchStmt] switch (...) {...}
-# 10| 0: [LocalVariableAccess] access to local variable x
-# 12| 0: [CaseStmt] case ...:
-# 12| 0: [DiscardPatternExpr] _
-# 12| 1: [BreakStmt] break;
-# 14| 3: [ExprStmt] ...;
-# 14| 0: [AssignExpr] ... = ...
-# 14| 0: [LocalVariableAccess] access to local variable x
+# 1| [Class] DefaultLiterals
+# 3| 5: [Method] f
+# 3| -1: [TypeMention] Void
+# 4| 4: [BlockStmt] {...}
+# 5| 0: [LocalVariableDeclStmt] ... ...;
+# 5| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 5| -1: [TypeMention] int
+# 5| 0: [LocalVariableAccess] access to local variable x
+# 5| 1: [CastExpr] (...) ...
+# 5| 1: [DefaultValueExpr] default
+# 5| 1: [LocalVariableDeclAndInitExpr] Int32 y = ...
+# 5| -1: [TypeMention] int
+# 5| 0: [LocalVariableAccess] access to local variable y
+# 5| 1: [DefaultValueExpr] default(...)
+# 5| 0: [TypeAccess] access to type Int32
+# 5| 0: [TypeMention] int
+# 6| 1: [IfStmt] if (...) ...
+# 6| 0: [EQExpr] ... == ...
+# 6| 0: [LocalVariableAccess] access to local variable x
+# 6| 1: [CastExpr] (...) ...
+# 6| 1: [DefaultValueExpr] default
+# 7| 1: [EmptyStmt] ;
+# 8| 2: [SwitchStmt] switch (...) {...}
+# 8| 0: [LocalVariableAccess] access to local variable x
+# 10| 0: [CaseStmt] case ...:
+# 10| 0: [DiscardPatternExpr] _
+# 10| 1: [BreakStmt] break;
+# 12| 3: [ExprStmt] ...;
+# 12| 0: [AssignExpr] ... = ...
+# 12| 0: [LocalVariableAccess] access to local variable x
+# 12| 1: [CastExpr] (...) ...
+# 12| 1: [DefaultValueExpr] default
+# 13| 4: [LocalVariableDeclStmt] ... ...;
+# 13| 0: [LocalVariableDeclAndInitExpr] String s = ...
+# 13| -1: [TypeMention] string
+# 13| 0: [LocalVariableAccess] access to local variable s
+# 13| 1: [CastExpr] (...) ...
+# 13| 1: [DefaultValueExpr] default
+# 14| 5: [LocalVariableDeclStmt] ... ...;
+# 14| 0: [LocalVariableDeclAndInitExpr] Boolean b = ...
+# 14| -1: [TypeMention] bool
+# 14| 0: [LocalVariableAccess] access to local variable b
# 14| 1: [CastExpr] (...) ...
# 14| 1: [DefaultValueExpr] default
-# 15| 4: [LocalVariableDeclStmt] ... ...;
-# 15| 0: [LocalVariableDeclAndInitExpr] String s = ...
-# 15| -1: [TypeMention] string
-# 15| 0: [LocalVariableAccess] access to local variable s
+# 15| 6: [LocalVariableDeclStmt] ... ...;
+# 15| 0: [LocalVariableDeclAndInitExpr] Double d = ...
+# 15| -1: [TypeMention] double
+# 15| 0: [LocalVariableAccess] access to local variable d
# 15| 1: [CastExpr] (...) ...
# 15| 1: [DefaultValueExpr] default
-# 16| 5: [LocalVariableDeclStmt] ... ...;
-# 16| 0: [LocalVariableDeclAndInitExpr] Boolean b = ...
-# 16| -1: [TypeMention] bool
-# 16| 0: [LocalVariableAccess] access to local variable b
-# 16| 1: [CastExpr] (...) ...
-# 16| 1: [DefaultValueExpr] default
-# 17| 6: [LocalVariableDeclStmt] ... ...;
-# 17| 0: [LocalVariableDeclAndInitExpr] Double d = ...
-# 17| -1: [TypeMention] double
-# 17| 0: [LocalVariableAccess] access to local variable d
-# 17| 1: [CastExpr] (...) ...
-# 17| 1: [DefaultValueExpr] default
-# 21| [Class] IsConstants
-# 23| 5: [Method] f
-# 23| -1: [TypeMention] Void
-# 24| 4: [BlockStmt] {...}
-# 25| 0: [LocalVariableDeclStmt] ... ...;
-# 25| 0: [LocalVariableDeclExpr] Boolean b
-# 25| 0: [TypeMention] bool
-# 26| 1: [ExprStmt] ...;
+# 19| [Class] IsConstants
+# 21| 5: [Method] f
+# 21| -1: [TypeMention] Void
+# 22| 4: [BlockStmt] {...}
+# 23| 0: [LocalVariableDeclStmt] ... ...;
+# 23| 0: [LocalVariableDeclExpr] Boolean b
+# 23| 0: [TypeMention] bool
+# 24| 1: [ExprStmt] ...;
+# 24| 0: [AssignExpr] ... = ...
+# 24| 0: [LocalVariableAccess] access to local variable b
+# 24| 1: [IsExpr] ... is ...
+# 24| 0: [ObjectCreation] object creation of type Object
+# 24| 0: [TypeMention] object
+# 24| 1: [ConstantPatternExpr,StringLiteral] "abc"
+# 25| 2: [ExprStmt] ...;
+# 25| 0: [AssignExpr] ... = ...
+# 25| 0: [LocalVariableAccess] access to local variable b
+# 25| 1: [IsExpr] ... is ...
+# 25| 0: [StringLiteral] ""
+# 25| 1: [ConstantPatternExpr,NullLiteral] null
+# 26| 3: [ExprStmt] ...;
# 26| 0: [AssignExpr] ... = ...
# 26| 0: [LocalVariableAccess] access to local variable b
# 26| 1: [IsExpr] ... is ...
-# 26| 0: [ObjectCreation] object creation of type Object
-# 26| 0: [TypeMention] object
-# 26| 1: [ConstantPatternExpr,StringLiteral] "abc"
-# 27| 2: [ExprStmt] ...;
-# 27| 0: [AssignExpr] ... = ...
-# 27| 0: [LocalVariableAccess] access to local variable b
-# 27| 1: [IsExpr] ... is ...
-# 27| 0: [StringLiteral] ""
-# 27| 1: [ConstantPatternExpr,NullLiteral] null
-# 28| 3: [ExprStmt] ...;
-# 28| 0: [AssignExpr] ... = ...
-# 28| 0: [LocalVariableAccess] access to local variable b
-# 28| 1: [IsExpr] ... is ...
-# 28| 0: [LocalVariableAccess] access to local variable b
-# 28| 1: [BoolLiteral,ConstantPatternExpr] true
+# 26| 0: [LocalVariableAccess] access to local variable b
+# 26| 1: [BoolLiteral,ConstantPatternExpr] true
diff --git a/csharp/ql/test/library-tests/csharp7.1/csharp71.cs b/csharp/ql/test/library-tests/csharp7.1/csharp71.cs
index 435dce31412..1852b369a9b 100644
--- a/csharp/ql/test/library-tests/csharp7.1/csharp71.cs
+++ b/csharp/ql/test/library-tests/csharp7.1/csharp71.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /langversion:latest
-
class DefaultLiterals
{
void f()
diff --git a/csharp/ql/test/library-tests/csharp7.1/options b/csharp/ql/test/library-tests/csharp7.1/options
new file mode 100644
index 00000000000..a87892aabd5
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp7.1/options
@@ -0,0 +1 @@
+semmle-extractor-options: /langversion:latest
diff --git a/csharp/ql/test/library-tests/csharp7.2/InArguments.expected b/csharp/ql/test/library-tests/csharp7.2/InArguments.expected
index 62e4085b707..915cdd0c51a 100644
--- a/csharp/ql/test/library-tests/csharp7.2/InArguments.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/InArguments.expected
@@ -1 +1 @@
-| csharp72.cs:18:12:18:12 | access to local variable s |
+| csharp72.cs:16:12:16:12 | access to local variable s |
diff --git a/csharp/ql/test/library-tests/csharp7.2/InParameters.expected b/csharp/ql/test/library-tests/csharp7.2/InParameters.expected
index e67f2c3c116..c20ac12ef73 100644
--- a/csharp/ql/test/library-tests/csharp7.2/InParameters.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/InParameters.expected
@@ -1 +1 @@
-| csharp72.cs:11:17:11:17 | s |
+| csharp72.cs:9:17:9:17 | s |
diff --git a/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected b/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected
index dcc6936de3f..04980cc04a4 100644
--- a/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected
@@ -1,2 +1,2 @@
-| csharp72.cs:48:23:48:34 | 85 |
-| csharp72.cs:53:31:53:31 | 1 |
+| csharp72.cs:46:23:46:34 | 85 |
+| csharp72.cs:51:31:51:31 | 1 |
diff --git a/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected
index f1d6b839b7c..39b7c407b74 100644
--- a/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected
@@ -1,49 +1,49 @@
csharp72.cs:
-# 5| [Class] InModifiers
-# 7| 5: [Struct] S
-# 11| 6: [Method] F
-# 11| -1: [TypeMention] Void
+# 3| [Class] InModifiers
+# 5| 5: [Struct] S
+# 9| 6: [Method] F
+# 9| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 11| 0: [Parameter] s
-# 11| -1: [TypeMention] S
-# 12| 4: [BlockStmt] {...}
-# 15| 7: [Method] CallF
-# 15| -1: [TypeMention] Void
-# 16| 4: [BlockStmt] {...}
-# 17| 0: [LocalVariableDeclStmt] ... ...;
-# 17| 0: [LocalVariableDeclAndInitExpr] S s = ...
-# 17| -1: [TypeMention] S
-# 17| 0: [LocalVariableAccess] access to local variable s
-# 17| 1: [ObjectCreation] object creation of type S
-# 17| 0: [TypeMention] S
-# 18| 1: [ExprStmt] ...;
-# 18| 0: [MethodCall] call to method F
-# 18| 0: [LocalVariableAccess] access to local variable s
-# 22| [Class] RefReadonlyReturns
-# 24| 5: [Field] s
+# 9| 0: [Parameter] s
+# 9| -1: [TypeMention] S
+# 10| 4: [BlockStmt] {...}
+# 13| 7: [Method] CallF
+# 13| -1: [TypeMention] Void
+# 14| 4: [BlockStmt] {...}
+# 15| 0: [LocalVariableDeclStmt] ... ...;
+# 15| 0: [LocalVariableDeclAndInitExpr] S s = ...
+# 15| -1: [TypeMention] S
+# 15| 0: [LocalVariableAccess] access to local variable s
+# 15| 1: [ObjectCreation] object creation of type S
+# 15| 0: [TypeMention] S
+# 16| 1: [ExprStmt] ...;
+# 16| 0: [MethodCall] call to method F
+# 16| 0: [LocalVariableAccess] access to local variable s
+# 20| [Class] RefReadonlyReturns
+# 22| 5: [Field] s
+# 22| -1: [TypeMention] int
+# 24| 6: [Method] F
# 24| -1: [TypeMention] int
-# 26| 6: [Method] F
-# 26| -1: [TypeMention] int
-# 27| 4: [BlockStmt] {...}
-# 28| 0: [ReturnStmt] return ...;
-# 28| 0: [RefExpr] ref ...
-# 28| 0: [FieldAccess] access to field s
-# 31| 7: [DelegateType] Del
-# 34| [Struct] ReadonlyStruct
-# 38| [Struct] RefStruct
-# 42| [Struct] ReadonlyRefStruct
-# 46| [Class] NumericLiterals
-# 48| 5: [Field] binaryValue
-# 48| -1: [TypeMention] int
-# 48| 1: [AssignExpr] ... = ...
-# 48| 0: [FieldAccess] access to field binaryValue
-# 48| 1: [IntLiteral] 85
-# 51| [Class] PrivateProtected
-# 53| 5: [Field] X
-# 53| -1: [TypeMention] int
-# 53| 1: [AssignExpr] ... = ...
-# 53| 0: [FieldAccess] access to field X
-# 53| 1: [IntLiteral] 1
-# 55| 6: [Method] F
-# 55| -1: [TypeMention] Void
-# 55| 4: [BlockStmt] {...}
+# 25| 4: [BlockStmt] {...}
+# 26| 0: [ReturnStmt] return ...;
+# 26| 0: [RefExpr] ref ...
+# 26| 0: [FieldAccess] access to field s
+# 29| 7: [DelegateType] Del
+# 32| [Struct] ReadonlyStruct
+# 36| [Struct] RefStruct
+# 40| [Struct] ReadonlyRefStruct
+# 44| [Class] NumericLiterals
+# 46| 5: [Field] binaryValue
+# 46| -1: [TypeMention] int
+# 46| 1: [AssignExpr] ... = ...
+# 46| 0: [FieldAccess] access to field binaryValue
+# 46| 1: [IntLiteral] 85
+# 49| [Class] PrivateProtected
+# 51| 5: [Field] X
+# 51| -1: [TypeMention] int
+# 51| 1: [AssignExpr] ... = ...
+# 51| 0: [FieldAccess] access to field X
+# 51| 1: [IntLiteral] 1
+# 53| 6: [Method] F
+# 53| -1: [TypeMention] Void
+# 53| 4: [BlockStmt] {...}
diff --git a/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected b/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected
index 4754b369a38..bb29fd3b461 100644
--- a/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected
@@ -1,2 +1,2 @@
-| csharp72.cs:53:27:53:27 | X |
-| csharp72.cs:55:28:55:28 | F |
+| csharp72.cs:51:27:51:27 | X |
+| csharp72.cs:53:28:53:28 | F |
diff --git a/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected b/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected
index 35b88cd6c01..55c23a42a70 100644
--- a/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected
@@ -1,2 +1,2 @@
-| csharp72.cs:34:17:34:30 | ReadonlyStruct |
-| csharp72.cs:42:21:42:37 | ReadonlyRefStruct |
+| csharp72.cs:32:17:32:30 | ReadonlyStruct |
+| csharp72.cs:40:21:40:37 | ReadonlyRefStruct |
diff --git a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected
index ceb92009b44..4ba44b85008 100644
--- a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected
@@ -1 +1 @@
-| csharp72.cs:31:31:31:33 | Del |
+| csharp72.cs:29:31:29:33 | Del |
diff --git a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected
index 86bbf1c956c..3f34bafaa06 100644
--- a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected
@@ -1 +1 @@
-| csharp72.cs:26:22:26:22 | F |
+| csharp72.cs:24:22:24:22 | F |
diff --git a/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected b/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected
index 92dd1d5020d..c1477b24d7c 100644
--- a/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected
+++ b/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected
@@ -1,2 +1,2 @@
-| csharp72.cs:38:12:38:20 | RefStruct |
-| csharp72.cs:42:21:42:37 | ReadonlyRefStruct |
+| csharp72.cs:36:12:36:20 | RefStruct |
+| csharp72.cs:40:21:40:37 | ReadonlyRefStruct |
diff --git a/csharp/ql/test/library-tests/csharp7.2/csharp72.cs b/csharp/ql/test/library-tests/csharp7.2/csharp72.cs
index 6844e005dec..b406c64fa66 100644
--- a/csharp/ql/test/library-tests/csharp7.2/csharp72.cs
+++ b/csharp/ql/test/library-tests/csharp7.2/csharp72.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /langversion:latest
-
using System;
class InModifiers
diff --git a/csharp/ql/test/library-tests/csharp7.2/options b/csharp/ql/test/library-tests/csharp7.2/options
new file mode 100644
index 00000000000..a87892aabd5
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp7.2/options
@@ -0,0 +1 @@
+semmle-extractor-options: /langversion:latest
diff --git a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
index b4f64e3bcd6..a6bb57b5f90 100644
--- a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
+++ b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
@@ -1,22 +1,22 @@
arrayCreation
-| csharp73.cs:9:20:9:49 | array creation of type Char* | 0 | csharp73.cs:9:20:9:49 | 2 |
-| csharp73.cs:10:20:10:45 | array creation of type Char* | 0 | csharp73.cs:10:36:10:36 | 1 |
-| csharp73.cs:11:20:11:37 | array creation of type Char[] | 0 | csharp73.cs:11:20:11:37 | 1 |
-| csharp73.cs:12:20:12:38 | array creation of type Char* | 0 | csharp73.cs:12:36:12:37 | 10 |
-| csharp73.cs:13:20:13:31 | array creation of type Char[] | 0 | csharp73.cs:13:29:13:30 | 10 |
-| csharp73.cs:22:29:22:47 | array creation of type Span | 0 | csharp73.cs:22:45:22:46 | 10 |
-| csharp73.cs:24:23:24:33 | array creation of type Int32[] | 0 | csharp73.cs:24:31:24:32 | 10 |
+| csharp73.cs:7:20:7:49 | array creation of type Char* | 0 | csharp73.cs:7:20:7:49 | 2 |
+| csharp73.cs:8:20:8:45 | array creation of type Char* | 0 | csharp73.cs:8:36:8:36 | 1 |
+| csharp73.cs:9:20:9:37 | array creation of type Char[] | 0 | csharp73.cs:9:20:9:37 | 1 |
+| csharp73.cs:10:20:10:38 | array creation of type Char* | 0 | csharp73.cs:10:36:10:37 | 10 |
+| csharp73.cs:11:20:11:31 | array creation of type Char[] | 0 | csharp73.cs:11:29:11:30 | 10 |
+| csharp73.cs:20:29:20:47 | array creation of type Span | 0 | csharp73.cs:20:45:20:46 | 10 |
+| csharp73.cs:22:23:22:33 | array creation of type Int32[] | 0 | csharp73.cs:22:31:22:32 | 10 |
arrayElement
-| csharp73.cs:9:20:9:49 | array creation of type Char* | 0 | csharp73.cs:9:40:9:42 | x |
-| csharp73.cs:9:20:9:49 | array creation of type Char* | 1 | csharp73.cs:9:45:9:47 | y |
-| csharp73.cs:10:20:10:45 | array creation of type Char* | 0 | csharp73.cs:10:41:10:43 | x |
-| csharp73.cs:11:20:11:37 | array creation of type Char[] | 0 | csharp73.cs:11:33:11:35 | x |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 0 | csharp73.cs:14:35:14:35 | 1 |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 1 | csharp73.cs:14:38:14:38 | 2 |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 2 | csharp73.cs:14:41:14:41 | 3 |
+| csharp73.cs:7:20:7:49 | array creation of type Char* | 0 | csharp73.cs:7:40:7:42 | x |
+| csharp73.cs:7:20:7:49 | array creation of type Char* | 1 | csharp73.cs:7:45:7:47 | y |
+| csharp73.cs:8:20:8:45 | array creation of type Char* | 0 | csharp73.cs:8:41:8:43 | x |
+| csharp73.cs:9:20:9:37 | array creation of type Char[] | 0 | csharp73.cs:9:33:9:35 | x |
+| csharp73.cs:12:20:12:43 | array creation of type Int32* | 0 | csharp73.cs:12:35:12:35 | 1 |
+| csharp73.cs:12:20:12:43 | array creation of type Int32* | 1 | csharp73.cs:12:38:12:38 | 2 |
+| csharp73.cs:12:20:12:43 | array creation of type Int32* | 2 | csharp73.cs:12:41:12:41 | 3 |
stackalloc
-| csharp73.cs:9:20:9:49 | array creation of type Char* |
-| csharp73.cs:10:20:10:45 | array creation of type Char* |
-| csharp73.cs:12:20:12:38 | array creation of type Char* |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* |
-| csharp73.cs:22:29:22:47 | array creation of type Span |
+| csharp73.cs:7:20:7:49 | array creation of type Char* |
+| csharp73.cs:8:20:8:45 | array creation of type Char* |
+| csharp73.cs:10:20:10:38 | array creation of type Char* |
+| csharp73.cs:12:20:12:43 | array creation of type Int32* |
+| csharp73.cs:20:29:20:47 | array creation of type Span |
diff --git a/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected
index b4d153b4c3c..05fdb3141f4 100644
--- a/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected
@@ -1,113 +1,113 @@
csharp73.cs:
-# 5| [Class] StackAllocs
-# 7| 5: [Method] Fn
-# 7| -1: [TypeMention] Void
-# 8| 4: [BlockStmt] {...}
-# 9| 0: [LocalVariableDeclStmt] ... ...;
-# 9| 0: [LocalVariableDeclAndInitExpr] Char* arr1 = ...
-# 9| -1: [TypeMention] char*
-# 9| 0: [LocalVariableAccess] access to local variable arr1
-# 9| 1: [Stackalloc] array creation of type Char*
-# 9| -2: [TypeMention] char*
+# 3| [Class] StackAllocs
+# 5| 5: [Method] Fn
+# 5| -1: [TypeMention] Void
+# 6| 4: [BlockStmt] {...}
+# 7| 0: [LocalVariableDeclStmt] ... ...;
+# 7| 0: [LocalVariableDeclAndInitExpr] Char* arr1 = ...
+# 7| -1: [TypeMention] char*
+# 7| 0: [LocalVariableAccess] access to local variable arr1
+# 7| 1: [Stackalloc] array creation of type Char*
+# 7| -2: [TypeMention] char*
+# 7| 1: [TypeMention] char
+# 7| -1: [ArrayInitializer] { ..., ... }
+# 7| 0: [CharLiteral] x
+# 7| 1: [CharLiteral] y
+# 8| 1: [LocalVariableDeclStmt] ... ...;
+# 8| 0: [LocalVariableDeclAndInitExpr] Char* arr2 = ...
+# 8| -1: [TypeMention] char*
+# 8| 0: [LocalVariableAccess] access to local variable arr2
+# 8| 1: [Stackalloc] array creation of type Char*
+# 8| -2: [TypeMention] char*
+# 8| 1: [TypeMention] char
+# 8| -1: [ArrayInitializer] { ..., ... }
+# 8| 0: [CharLiteral] x
+# 8| 0: [IntLiteral] 1
+# 9| 2: [LocalVariableDeclStmt] ... ...;
+# 9| 0: [LocalVariableDeclAndInitExpr] Char[] arr3 = ...
+# 9| -1: [TypeMention] Char[]
+# 9| 0: [LocalVariableAccess] access to local variable arr3
+# 9| 1: [ArrayCreation] array creation of type Char[]
+# 9| -2: [TypeMention] Char[]
# 9| 1: [TypeMention] char
# 9| -1: [ArrayInitializer] { ..., ... }
# 9| 0: [CharLiteral] x
-# 9| 1: [CharLiteral] y
-# 10| 1: [LocalVariableDeclStmt] ... ...;
-# 10| 0: [LocalVariableDeclAndInitExpr] Char* arr2 = ...
+# 10| 3: [LocalVariableDeclStmt] ... ...;
+# 10| 0: [LocalVariableDeclAndInitExpr] Char* arr4 = ...
# 10| -1: [TypeMention] char*
-# 10| 0: [LocalVariableAccess] access to local variable arr2
+# 10| 0: [LocalVariableAccess] access to local variable arr4
# 10| 1: [Stackalloc] array creation of type Char*
-# 10| -2: [TypeMention] char*
+# 10| -1: [TypeMention] char*
# 10| 1: [TypeMention] char
-# 10| -1: [ArrayInitializer] { ..., ... }
-# 10| 0: [CharLiteral] x
-# 10| 0: [IntLiteral] 1
-# 11| 2: [LocalVariableDeclStmt] ... ...;
-# 11| 0: [LocalVariableDeclAndInitExpr] Char[] arr3 = ...
+# 10| 0: [IntLiteral] 10
+# 11| 4: [LocalVariableDeclStmt] ... ...;
+# 11| 0: [LocalVariableDeclAndInitExpr] Char[] arr5 = ...
# 11| -1: [TypeMention] Char[]
-# 11| 0: [LocalVariableAccess] access to local variable arr3
+# 11| 0: [LocalVariableAccess] access to local variable arr5
# 11| 1: [ArrayCreation] array creation of type Char[]
-# 11| -2: [TypeMention] Char[]
+# 11| -1: [TypeMention] Char[]
# 11| 1: [TypeMention] char
-# 11| -1: [ArrayInitializer] { ..., ... }
-# 11| 0: [CharLiteral] x
-# 12| 3: [LocalVariableDeclStmt] ... ...;
-# 12| 0: [LocalVariableDeclAndInitExpr] Char* arr4 = ...
-# 12| -1: [TypeMention] char*
-# 12| 0: [LocalVariableAccess] access to local variable arr4
-# 12| 1: [Stackalloc] array creation of type Char*
-# 12| -1: [TypeMention] char*
-# 12| 1: [TypeMention] char
-# 12| 0: [IntLiteral] 10
-# 13| 4: [LocalVariableDeclStmt] ... ...;
-# 13| 0: [LocalVariableDeclAndInitExpr] Char[] arr5 = ...
-# 13| -1: [TypeMention] Char[]
-# 13| 0: [LocalVariableAccess] access to local variable arr5
-# 13| 1: [ArrayCreation] array creation of type Char[]
-# 13| -1: [TypeMention] Char[]
-# 13| 1: [TypeMention] char
-# 13| 0: [IntLiteral] 10
-# 14| 5: [LocalVariableDeclStmt] ... ...;
-# 14| 0: [LocalVariableDeclAndInitExpr] Int32* arr6 = ...
-# 14| -1: [TypeMention] int*
-# 14| 0: [LocalVariableAccess] access to local variable arr6
-# 14| 1: [Stackalloc] array creation of type Int32*
-# 14| -1: [ArrayInitializer] { ..., ... }
-# 14| 0: [IntLiteral] 1
-# 14| 1: [IntLiteral] 2
-# 14| 2: [IntLiteral] 3
-# 18| [Class] PinnedReference
-# 20| 5: [Method] F
-# 20| -1: [TypeMention] Void
-# 21| 4: [BlockStmt] {...}
-# 22| 0: [LocalVariableDeclStmt] ... ...;
-# 22| 0: [LocalVariableDeclAndInitExpr] Span buffer = ...
-# 22| -1: [TypeMention] Span
-# 22| 1: [TypeMention] byte
-# 22| 0: [LocalVariableAccess] access to local variable buffer
-# 22| 1: [Stackalloc] array creation of type Span
-# 22| -1: [TypeMention] Span
-# 22| 1: [TypeMention] byte
-# 22| 0: [IntLiteral] 10
-# 24| 1: [LocalVariableDeclStmt] ... ...;
-# 24| 0: [LocalVariableDeclAndInitExpr] Span t = ...
-# 24| -1: [TypeMention] Span
-# 24| 1: [TypeMention] int
-# 24| 0: [LocalVariableAccess] access to local variable t
-# 24| 1: [OperatorCall] call to operator implicit conversion
-# 24| 0: [ArrayCreation] array creation of type Int32[]
-# 24| -1: [TypeMention] Int32[]
-# 24| 1: [TypeMention] int
-# 24| 0: [IntLiteral] 10
-# 27| 2: [BlockStmt] {...}
-# 32| [Class] UnmanagedConstraint<>
+# 11| 0: [IntLiteral] 10
+# 12| 5: [LocalVariableDeclStmt] ... ...;
+# 12| 0: [LocalVariableDeclAndInitExpr] Int32* arr6 = ...
+# 12| -1: [TypeMention] int*
+# 12| 0: [LocalVariableAccess] access to local variable arr6
+# 12| 1: [Stackalloc] array creation of type Int32*
+# 12| -1: [ArrayInitializer] { ..., ... }
+# 12| 0: [IntLiteral] 1
+# 12| 1: [IntLiteral] 2
+# 12| 2: [IntLiteral] 3
+# 16| [Class] PinnedReference
+# 18| 5: [Method] F
+# 18| -1: [TypeMention] Void
+# 19| 4: [BlockStmt] {...}
+# 20| 0: [LocalVariableDeclStmt] ... ...;
+# 20| 0: [LocalVariableDeclAndInitExpr] Span buffer = ...
+# 20| -1: [TypeMention] Span
+# 20| 1: [TypeMention] byte
+# 20| 0: [LocalVariableAccess] access to local variable buffer
+# 20| 1: [Stackalloc] array creation of type Span
+# 20| -1: [TypeMention] Span
+# 20| 1: [TypeMention] byte
+# 20| 0: [IntLiteral] 10
+# 22| 1: [LocalVariableDeclStmt] ... ...;
+# 22| 0: [LocalVariableDeclAndInitExpr] Span t = ...
+# 22| -1: [TypeMention] Span
+# 22| 1: [TypeMention] int
+# 22| 0: [LocalVariableAccess] access to local variable t
+# 22| 1: [OperatorCall] call to operator implicit conversion
+# 22| 0: [ArrayCreation] array creation of type Int32[]
+# 22| -1: [TypeMention] Int32[]
+# 22| 1: [TypeMention] int
+# 22| 0: [IntLiteral] 10
+# 25| 2: [BlockStmt] {...}
+# 30| [Class] UnmanagedConstraint<>
#-----| 1: (Type parameters)
-# 32| 0: [TypeParameter] T
-# 36| [Class] EnumConstraint<>
+# 30| 0: [TypeParameter] T
+# 34| [Class] EnumConstraint<>
#-----| 1: (Type parameters)
-# 36| 0: [TypeParameter] T
-# 40| [Class] DelegateConstraint<>
+# 34| 0: [TypeParameter] T
+# 38| [Class] DelegateConstraint<>
#-----| 1: (Type parameters)
-# 40| 0: [TypeParameter] T
-# 44| [Class] ExpressionVariables
-# 46| 4: [InstanceConstructor] ExpressionVariables
+# 38| 0: [TypeParameter] T
+# 42| [Class] ExpressionVariables
+# 44| 4: [InstanceConstructor] ExpressionVariables
#-----| 2: (Parameters)
-# 46| 0: [Parameter] x
-# 46| -1: [TypeMention] int
-# 47| 4: [BlockStmt] {...}
-# 48| 0: [ExprStmt] ...;
-# 48| 0: [AssignExpr] ... = ...
-# 48| 0: [ParameterAccess] access to parameter x
-# 48| 1: [IntLiteral] 5
-# 51| 5: [InstanceConstructor] ExpressionVariables
-# 51| 3: [ConstructorInitializer] call to constructor ExpressionVariables
-# 51| 0: [LocalVariableDeclExpr] Int32 x
-# 52| 4: [BlockStmt] {...}
-# 53| 0: [ExprStmt] ...;
-# 53| 0: [MethodCall] call to method WriteLine
-# 53| -1: [TypeAccess] access to type Console
-# 53| 0: [TypeMention] Console
-# 53| 0: [InterpolatedStringExpr] $"..."
-# 53| 0: [StringLiteral] "x is "
-# 53| 1: [LocalVariableAccess] access to local variable x
+# 44| 0: [Parameter] x
+# 44| -1: [TypeMention] int
+# 45| 4: [BlockStmt] {...}
+# 46| 0: [ExprStmt] ...;
+# 46| 0: [AssignExpr] ... = ...
+# 46| 0: [ParameterAccess] access to parameter x
+# 46| 1: [IntLiteral] 5
+# 49| 5: [InstanceConstructor] ExpressionVariables
+# 49| 3: [ConstructorInitializer] call to constructor ExpressionVariables
+# 49| 0: [LocalVariableDeclExpr] Int32 x
+# 50| 4: [BlockStmt] {...}
+# 51| 0: [ExprStmt] ...;
+# 51| 0: [MethodCall] call to method WriteLine
+# 51| -1: [TypeAccess] access to type Console
+# 51| 0: [TypeMention] Console
+# 51| 0: [InterpolatedStringExpr] $"..."
+# 51| 0: [StringLiteral] "x is "
+# 51| 1: [LocalVariableAccess] access to local variable x
diff --git a/csharp/ql/test/library-tests/csharp7.3/csharp73.cs b/csharp/ql/test/library-tests/csharp7.3/csharp73.cs
index d1a38ae9227..6588382627b 100644
--- a/csharp/ql/test/library-tests/csharp7.3/csharp73.cs
+++ b/csharp/ql/test/library-tests/csharp7.3/csharp73.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /langversion:latest
-
using System;
class StackAllocs
diff --git a/csharp/ql/test/library-tests/csharp7.3/options b/csharp/ql/test/library-tests/csharp7.3/options
new file mode 100644
index 00000000000..a87892aabd5
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp7.3/options
@@ -0,0 +1 @@
+semmle-extractor-options: /langversion:latest
diff --git a/csharp/ql/test/library-tests/csharp7/Access.expected b/csharp/ql/test/library-tests/csharp7/Access.expected
index f60b0c23d67..f6b95bfd5b1 100644
--- a/csharp/ql/test/library-tests/csharp7/Access.expected
+++ b/csharp/ql/test/library-tests/csharp7/Access.expected
@@ -1,12 +1,12 @@
-| CSharp7.cs:51:22:51:23 | String t1 | write |
-| CSharp7.cs:52:19:52:20 | String t2 | write |
-| CSharp7.cs:53:13:53:14 | access to local variable t3 | write |
-| CSharp7.cs:53:18:53:19 | access to local variable t1 | read |
-| CSharp7.cs:54:15:54:16 | access to local variable t1 | write |
-| CSharp7.cs:55:9:55:10 | access to local variable t3 | write |
-| CSharp7.cs:55:14:55:15 | access to local variable t1 | read |
-| CSharp7.cs:56:9:56:10 | access to local variable t3 | write |
-| CSharp7.cs:56:14:56:15 | access to local variable t2 | read |
-| CSharp7.cs:57:30:57:31 | String t4 | write |
-| CSharp7.cs:58:13:58:14 | access to local variable t5 | write |
-| CSharp7.cs:58:18:58:19 | access to local variable t4 | read |
+| CSharp7.cs:49:22:49:23 | String t1 | write |
+| CSharp7.cs:50:19:50:20 | String t2 | write |
+| CSharp7.cs:51:13:51:14 | access to local variable t3 | write |
+| CSharp7.cs:51:18:51:19 | access to local variable t1 | read |
+| CSharp7.cs:52:15:52:16 | access to local variable t1 | write |
+| CSharp7.cs:53:9:53:10 | access to local variable t3 | write |
+| CSharp7.cs:53:14:53:15 | access to local variable t1 | read |
+| CSharp7.cs:54:9:54:10 | access to local variable t3 | write |
+| CSharp7.cs:54:14:54:15 | access to local variable t2 | read |
+| CSharp7.cs:55:30:55:31 | String t4 | write |
+| CSharp7.cs:56:13:56:14 | access to local variable t5 | write |
+| CSharp7.cs:56:18:56:19 | access to local variable t4 | read |
diff --git a/csharp/ql/test/library-tests/csharp7/CSharp7.cs b/csharp/ql/test/library-tests/csharp7/CSharp7.cs
index 0339ccc8728..c17b4164120 100644
--- a/csharp/ql/test/library-tests/csharp7/CSharp7.cs
+++ b/csharp/ql/test/library-tests/csharp7/CSharp7.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /r:System.Linq.dll
-
using System;
using System.Linq;
using System.Collections.Generic;
diff --git a/csharp/ql/test/library-tests/csharp7/CaseCondition.expected b/csharp/ql/test/library-tests/csharp7/CaseCondition.expected
index f538575183e..80683030f39 100644
--- a/csharp/ql/test/library-tests/csharp7/CaseCondition.expected
+++ b/csharp/ql/test/library-tests/csharp7/CaseCondition.expected
@@ -1,3 +1,3 @@
-| CSharp7.cs:254:13:254:31 | case ...: | CSharp7.cs:254:26:254:30 | ... < ... |
-| CSharp7.cs:256:13:256:41 | case ...: | CSharp7.cs:256:27:256:40 | ... is ... |
-| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:30:259:35 | ... > ... |
+| CSharp7.cs:252:13:252:31 | case ...: | CSharp7.cs:252:26:252:30 | ... < ... |
+| CSharp7.cs:254:13:254:41 | case ...: | CSharp7.cs:254:27:254:40 | ... is ... |
+| CSharp7.cs:257:13:257:36 | case ...: | CSharp7.cs:257:30:257:35 | ... > ... |
diff --git a/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected
index a945d262198..0ec863639e8 100644
--- a/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp7/ConstructedLocalFunctions.expected
@@ -1,4 +1,4 @@
-| CSharp7.cs:161:9:161:24 | f | f() | f() |
-| CSharp7.cs:162:9:162:25 | g | g(U) | g(T) |
-| CSharp7.cs:164:9:169:9 | h | h(int, int) | h(T, U) |
-| CSharp7.cs:164:9:169:9 | h | h(string, bool) | h(T, U) |
+| CSharp7.cs:159:9:159:24 | f | f() | f() |
+| CSharp7.cs:160:9:160:25 | g | g(U) | g(T) |
+| CSharp7.cs:162:9:167:9 | h | h(int, int) | h(T, U) |
+| CSharp7.cs:162:9:167:9 | h | h(string, bool) | h(T, U) |
diff --git a/csharp/ql/test/library-tests/csharp7/DefUse.expected b/csharp/ql/test/library-tests/csharp7/DefUse.expected
index 62cc5ea4b1b..fb55afb5e51 100644
--- a/csharp/ql/test/library-tests/csharp7/DefUse.expected
+++ b/csharp/ql/test/library-tests/csharp7/DefUse.expected
@@ -1,75 +1,75 @@
-| CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:24:22:28 | access to parameter value |
-| CSharp7.cs:31:19:31:19 | i | CSharp7.cs:33:16:33:16 | access to parameter i |
-| CSharp7.cs:31:19:31:19 | i | CSharp7.cs:33:24:33:24 | access to parameter i |
-| CSharp7.cs:44:19:44:19 | x | CSharp7.cs:46:13:46:13 | access to parameter x |
-| CSharp7.cs:51:22:51:23 | String t1 | CSharp7.cs:53:18:53:19 | access to local variable t1 |
-| CSharp7.cs:52:19:52:20 | String t2 | CSharp7.cs:56:14:56:15 | access to local variable t2 |
-| CSharp7.cs:54:15:54:16 | access to local variable t1 | CSharp7.cs:55:14:55:15 | access to local variable t1 |
-| CSharp7.cs:57:30:57:31 | String t4 | CSharp7.cs:58:18:58:19 | access to local variable t4 |
-| CSharp7.cs:72:13:72:19 | (Int32,Int32) z = ... | CSharp7.cs:75:16:75:16 | access to local variable z |
-| CSharp7.cs:72:13:72:19 | (Int32,Int32) z = ... | CSharp7.cs:77:39:77:39 | access to local variable z |
-| CSharp7.cs:76:9:76:32 | ... = ... | CSharp7.cs:79:27:79:27 | access to local variable x |
-| CSharp7.cs:77:9:77:40 | ... = ... | CSharp7.cs:78:24:78:24 | access to local variable b |
-| CSharp7.cs:77:9:77:40 | ... = ... | CSharp7.cs:78:28:78:28 | access to local variable c |
-| CSharp7.cs:77:9:77:40 | ... = ... | CSharp7.cs:78:31:78:31 | access to local variable a |
-| CSharp7.cs:82:21:82:21 | x | CSharp7.cs:84:20:84:20 | access to parameter x |
-| CSharp7.cs:89:13:89:34 | (String,String) t1 = ... | CSharp7.cs:90:28:90:29 | access to local variable t1 |
-| CSharp7.cs:89:13:89:34 | (String,String) t1 = ... | CSharp7.cs:92:20:92:21 | access to local variable t1 |
-| CSharp7.cs:90:9:90:29 | ... = ... | CSharp7.cs:91:18:91:19 | access to local variable t3 |
-| CSharp7.cs:109:9:109:46 | ... = ... | CSharp7.cs:112:27:112:28 | access to local variable m1 |
-| CSharp7.cs:109:9:109:46 | ... = ... | CSharp7.cs:112:31:112:32 | access to local variable m2 |
-| CSharp7.cs:112:9:112:33 | ... = ... | CSharp7.cs:113:18:113:19 | access to local variable m4 |
-| CSharp7.cs:114:9:114:67 | ... = ... | CSharp7.cs:115:19:115:20 | access to local variable m9 |
-| CSharp7.cs:114:38:114:67 | ... = ... | CSharp7.cs:118:9:118:10 | access to local variable m2 |
-| CSharp7.cs:114:38:114:67 | ... = ... | CSharp7.cs:119:19:119:20 | access to local variable m2 |
-| CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:32:131:32 | access to parameter x |
-| CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:39:133:39 | access to parameter t |
-| CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:34:139:34 | access to parameter x |
-| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:26:141:26 | access to parameter x |
-| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:41:141:41 | access to parameter x |
-| CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:29:143:29 | access to parameter x |
-| CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x |
-| CSharp7.cs:162:18:162:18 | t | CSharp7.cs:162:24:162:24 | access to parameter t |
-| CSharp7.cs:164:26:164:26 | u | CSharp7.cs:168:22:168:22 | access to parameter u |
-| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:182:23:182:25 | access to local variable src |
-| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:183:23:183:25 | access to local variable src |
-| CSharp7.cs:177:16:177:30 | String src = ... | CSharp7.cs:184:23:184:25 | access to local variable src |
-| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:33:178:33 | access to parameter s |
-| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:31:179:31 | access to parameter s |
-| CSharp7.cs:180:25:180:25 | s | CSharp7.cs:180:37:180:37 | access to parameter s |
-| CSharp7.cs:192:13:192:18 | Int32 v1 = ... | CSharp7.cs:193:26:193:27 | access to local variable v1 |
-| CSharp7.cs:192:13:192:18 | Int32 v1 = ... | CSharp7.cs:199:21:199:22 | access to local variable v1 |
-| CSharp7.cs:194:13:194:31 | Int32[] array = ... | CSharp7.cs:196:14:196:18 | access to local variable array |
-| CSharp7.cs:194:13:194:31 | Int32[] array = ... | CSharp7.cs:197:26:197:30 | access to local variable array |
-| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:198:26:198:27 | access to local variable r1 |
-| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:200:33:200:34 | access to local variable r1 |
-| CSharp7.cs:196:9:196:21 | ... = ... | CSharp7.cs:201:16:201:17 | access to local variable r1 |
-| CSharp7.cs:204:24:204:24 | p | CSharp7.cs:207:20:207:20 | access to parameter p |
-| CSharp7.cs:206:28:206:28 | q | CSharp7.cs:206:44:206:44 | access to parameter q |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:235:13:235:13 | access to local variable o |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:239:18:239:18 | access to local variable o |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:243:18:243:18 | access to local variable o |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:246:18:246:18 | access to local variable o |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:250:17:250:17 | access to local variable o |
-| CSharp7.cs:234:16:234:23 | Object o = ... | CSharp7.cs:256:27:256:27 | access to local variable o |
-| CSharp7.cs:235:18:235:23 | Int32 i1 | CSharp7.cs:235:28:235:29 | access to local variable i1 |
-| CSharp7.cs:235:18:235:23 | Int32 i1 | CSharp7.cs:237:38:237:39 | access to local variable i1 |
-| CSharp7.cs:239:23:239:31 | String s1 | CSharp7.cs:241:41:241:42 | access to local variable s1 |
-| CSharp7.cs:256:32:256:40 | String s4 | CSharp7.cs:257:40:257:41 | access to local variable s4 |
-| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:259:30:259:31 | access to local variable i2 |
-| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:260:47:260:48 | access to local variable i2 |
-| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:263:42:263:43 | access to local variable i3 |
-| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:266:45:266:46 | access to local variable s2 |
-| CSharp7.cs:284:13:284:48 | Dictionary dict = ... | CSharp7.cs:285:20:285:23 | access to local variable dict |
-| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:287:39:287:42 | access to local variable list |
-| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:289:36:289:39 | access to local variable list |
-| CSharp7.cs:285:13:285:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:291:32:291:35 | access to local variable list |
-| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:41:285:44 | access to parameter item |
-| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:51:285:54 | access to parameter item |
-| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:25:299:25 | access to local variable x |
-| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:35:299:35 | access to local variable x |
-| CSharp7.cs:299:18:299:22 | Int32 x = ... | CSharp7.cs:299:49:299:49 | access to local variable x |
-| CSharp7.cs:299:40:299:44 | Int32 y | CSharp7.cs:301:31:301:31 | access to local variable y |
-| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:25:299:25 | access to local variable x |
-| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:35:299:35 | access to local variable x |
-| CSharp7.cs:299:47:299:49 | ++... | CSharp7.cs:299:49:299:49 | access to local variable x |
+| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:24:20:28 | access to parameter value |
+| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:31:16:31:16 | access to parameter i |
+| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:31:24:31:24 | access to parameter i |
+| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:44:13:44:13 | access to parameter x |
+| CSharp7.cs:49:22:49:23 | String t1 | CSharp7.cs:51:18:51:19 | access to local variable t1 |
+| CSharp7.cs:50:19:50:20 | String t2 | CSharp7.cs:54:14:54:15 | access to local variable t2 |
+| CSharp7.cs:52:15:52:16 | access to local variable t1 | CSharp7.cs:53:14:53:15 | access to local variable t1 |
+| CSharp7.cs:55:30:55:31 | String t4 | CSharp7.cs:56:18:56:19 | access to local variable t4 |
+| CSharp7.cs:70:13:70:19 | (Int32,Int32) z = ... | CSharp7.cs:73:16:73:16 | access to local variable z |
+| CSharp7.cs:70:13:70:19 | (Int32,Int32) z = ... | CSharp7.cs:75:39:75:39 | access to local variable z |
+| CSharp7.cs:74:9:74:32 | ... = ... | CSharp7.cs:77:27:77:27 | access to local variable x |
+| CSharp7.cs:75:9:75:40 | ... = ... | CSharp7.cs:76:24:76:24 | access to local variable b |
+| CSharp7.cs:75:9:75:40 | ... = ... | CSharp7.cs:76:28:76:28 | access to local variable c |
+| CSharp7.cs:75:9:75:40 | ... = ... | CSharp7.cs:76:31:76:31 | access to local variable a |
+| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:82:20:82:20 | access to parameter x |
+| CSharp7.cs:87:13:87:34 | (String,String) t1 = ... | CSharp7.cs:88:28:88:29 | access to local variable t1 |
+| CSharp7.cs:87:13:87:34 | (String,String) t1 = ... | CSharp7.cs:90:20:90:21 | access to local variable t1 |
+| CSharp7.cs:88:9:88:29 | ... = ... | CSharp7.cs:89:18:89:19 | access to local variable t3 |
+| CSharp7.cs:107:9:107:46 | ... = ... | CSharp7.cs:110:27:110:28 | access to local variable m1 |
+| CSharp7.cs:107:9:107:46 | ... = ... | CSharp7.cs:110:31:110:32 | access to local variable m2 |
+| CSharp7.cs:110:9:110:33 | ... = ... | CSharp7.cs:111:18:111:19 | access to local variable m4 |
+| CSharp7.cs:112:9:112:67 | ... = ... | CSharp7.cs:113:19:113:20 | access to local variable m9 |
+| CSharp7.cs:112:38:112:67 | ... = ... | CSharp7.cs:116:9:116:10 | access to local variable m2 |
+| CSharp7.cs:112:38:112:67 | ... = ... | CSharp7.cs:117:19:117:20 | access to local variable m2 |
+| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:32:129:32 | access to parameter x |
+| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:39:131:39 | access to parameter t |
+| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:34:137:34 | access to parameter x |
+| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:26:139:26 | access to parameter x |
+| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:41:139:41 | access to parameter x |
+| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:29:141:29 | access to parameter x |
+| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:33:145:33 | access to parameter x |
+| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:24:160:24 | access to parameter t |
+| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:166:22:166:22 | access to parameter u |
+| CSharp7.cs:175:16:175:30 | String src = ... | CSharp7.cs:180:23:180:25 | access to local variable src |
+| CSharp7.cs:175:16:175:30 | String src = ... | CSharp7.cs:181:23:181:25 | access to local variable src |
+| CSharp7.cs:175:16:175:30 | String src = ... | CSharp7.cs:182:23:182:25 | access to local variable src |
+| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:33:176:33 | access to parameter s |
+| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:31:177:31 | access to parameter s |
+| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:37:178:37 | access to parameter s |
+| CSharp7.cs:190:13:190:18 | Int32 v1 = ... | CSharp7.cs:191:26:191:27 | access to local variable v1 |
+| CSharp7.cs:190:13:190:18 | Int32 v1 = ... | CSharp7.cs:197:21:197:22 | access to local variable v1 |
+| CSharp7.cs:192:13:192:31 | Int32[] array = ... | CSharp7.cs:194:14:194:18 | access to local variable array |
+| CSharp7.cs:192:13:192:31 | Int32[] array = ... | CSharp7.cs:195:26:195:30 | access to local variable array |
+| CSharp7.cs:194:9:194:21 | ... = ... | CSharp7.cs:196:26:196:27 | access to local variable r1 |
+| CSharp7.cs:194:9:194:21 | ... = ... | CSharp7.cs:198:33:198:34 | access to local variable r1 |
+| CSharp7.cs:194:9:194:21 | ... = ... | CSharp7.cs:199:16:199:17 | access to local variable r1 |
+| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:205:20:205:20 | access to parameter p |
+| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:44:204:44 | access to parameter q |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:233:13:233:13 | access to local variable o |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:237:18:237:18 | access to local variable o |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:241:18:241:18 | access to local variable o |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:244:18:244:18 | access to local variable o |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:248:17:248:17 | access to local variable o |
+| CSharp7.cs:232:16:232:23 | Object o = ... | CSharp7.cs:254:27:254:27 | access to local variable o |
+| CSharp7.cs:233:18:233:23 | Int32 i1 | CSharp7.cs:233:28:233:29 | access to local variable i1 |
+| CSharp7.cs:233:18:233:23 | Int32 i1 | CSharp7.cs:235:38:235:39 | access to local variable i1 |
+| CSharp7.cs:237:23:237:31 | String s1 | CSharp7.cs:239:41:239:42 | access to local variable s1 |
+| CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:255:40:255:41 | access to local variable s4 |
+| CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:257:30:257:31 | access to local variable i2 |
+| CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:258:47:258:48 | access to local variable i2 |
+| CSharp7.cs:260:18:260:23 | Int32 i3 | CSharp7.cs:261:42:261:43 | access to local variable i3 |
+| CSharp7.cs:263:18:263:26 | String s2 | CSharp7.cs:264:45:264:46 | access to local variable s2 |
+| CSharp7.cs:282:13:282:48 | Dictionary dict = ... | CSharp7.cs:283:20:283:23 | access to local variable dict |
+| CSharp7.cs:283:13:283:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:285:39:285:42 | access to local variable list |
+| CSharp7.cs:283:13:283:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:287:36:287:39 | access to local variable list |
+| CSharp7.cs:283:13:283:62 | IEnumerable<(Int32,String)> list = ... | CSharp7.cs:289:32:289:35 | access to local variable list |
+| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:41:283:44 | access to parameter item |
+| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:51:283:54 | access to parameter item |
+| CSharp7.cs:297:18:297:22 | Int32 x = ... | CSharp7.cs:297:25:297:25 | access to local variable x |
+| CSharp7.cs:297:18:297:22 | Int32 x = ... | CSharp7.cs:297:35:297:35 | access to local variable x |
+| CSharp7.cs:297:18:297:22 | Int32 x = ... | CSharp7.cs:297:49:297:49 | access to local variable x |
+| CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:299:31:299:31 | access to local variable y |
+| CSharp7.cs:297:47:297:49 | ++... | CSharp7.cs:297:25:297:25 | access to local variable x |
+| CSharp7.cs:297:47:297:49 | ++... | CSharp7.cs:297:35:297:35 | access to local variable x |
+| CSharp7.cs:297:47:297:49 | ++... | CSharp7.cs:297:49:297:49 | access to local variable x |
diff --git a/csharp/ql/test/library-tests/csharp7/Discards.expected b/csharp/ql/test/library-tests/csharp7/Discards.expected
index 0fffde7c1c0..7d8e6f7ea5f 100644
--- a/csharp/ql/test/library-tests/csharp7/Discards.expected
+++ b/csharp/ql/test/library-tests/csharp7/Discards.expected
@@ -1,8 +1,8 @@
-| CSharp7.cs:223:9:223:9 | _ | (Int32,Double) |
-| CSharp7.cs:223:19:223:19 | _ | Boolean |
+| CSharp7.cs:221:9:221:9 | _ | (Int32,Double) |
+| CSharp7.cs:221:19:221:19 | _ | Boolean |
+| CSharp7.cs:222:10:222:10 | _ | Int32 |
+| CSharp7.cs:222:13:222:13 | _ | Double |
+| CSharp7.cs:222:24:222:24 | _ | Boolean |
+| CSharp7.cs:223:17:223:17 | _ | Double |
+| CSharp7.cs:223:28:223:28 | _ | Boolean |
| CSharp7.cs:224:10:224:10 | _ | Int32 |
-| CSharp7.cs:224:13:224:13 | _ | Double |
-| CSharp7.cs:224:24:224:24 | _ | Boolean |
-| CSharp7.cs:225:17:225:17 | _ | Double |
-| CSharp7.cs:225:28:225:28 | _ | Boolean |
-| CSharp7.cs:226:10:226:10 | _ | Int32 |
diff --git a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected
index 5a09ce22d43..fcba5499d77 100644
--- a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected
+++ b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected
@@ -1,18 +1,18 @@
-| CSharp7.cs:17:9:17:11 | Foo | CSharp7.cs:17:18:17:22 | access to field field |
-| CSharp7.cs:18:14:18:14 | get_P | CSharp7.cs:18:14:18:14 | 5 |
-| CSharp7.cs:21:9:21:11 | get_Q | CSharp7.cs:21:16:21:20 | call to method Foo |
-| CSharp7.cs:22:9:22:11 | set_Q | CSharp7.cs:22:16:22:28 | ... = ... |
-| CSharp7.cs:25:5:25:27 | ExpressionBodiedMembers | CSharp7.cs:25:39:25:43 | call to method Foo |
-| CSharp7.cs:26:6:26:28 | ~ExpressionBodiedMembers | CSharp7.cs:26:35:26:39 | call to method Foo |
-| CSharp7.cs:137:9:137:22 | f3 | CSharp7.cs:137:21:137:21 | 2 |
-| CSharp7.cs:139:29:139:38 | (...) => ... | CSharp7.cs:139:34:139:38 | ... + ... |
-| CSharp7.cs:141:9:141:51 | f6 | CSharp7.cs:141:26:141:50 | ... ? ... : ... |
-| CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:26:143:30 | call to local function f6 |
-| CSharp7.cs:147:13:147:35 | f9 | CSharp7.cs:147:30:147:34 | call to local function f7 |
-| CSharp7.cs:153:13:153:26 | f9 | CSharp7.cs:153:25:153:25 | 0 |
-| CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:23:161:23 | 1 |
-| CSharp7.cs:162:9:162:25 | g | CSharp7.cs:162:24:162:24 | access to parameter t |
-| CSharp7.cs:166:13:166:43 | f2 | CSharp7.cs:166:37:166:42 | call to local function f |
-| CSharp7.cs:178:9:178:40 | f | CSharp7.cs:178:31:178:39 | ... + ... |
-| CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:31:179:31 | access to parameter s |
-| CSharp7.cs:285:32:285:61 | (...) => ... | CSharp7.cs:285:40:285:61 | (..., ...) |
+| CSharp7.cs:15:9:15:11 | Foo | CSharp7.cs:15:18:15:22 | access to field field |
+| CSharp7.cs:16:14:16:14 | get_P | CSharp7.cs:16:14:16:14 | 5 |
+| CSharp7.cs:19:9:19:11 | get_Q | CSharp7.cs:19:16:19:20 | call to method Foo |
+| CSharp7.cs:20:9:20:11 | set_Q | CSharp7.cs:20:16:20:28 | ... = ... |
+| CSharp7.cs:23:5:23:27 | ExpressionBodiedMembers | CSharp7.cs:23:39:23:43 | call to method Foo |
+| CSharp7.cs:24:6:24:28 | ~ExpressionBodiedMembers | CSharp7.cs:24:35:24:39 | call to method Foo |
+| CSharp7.cs:135:9:135:22 | f3 | CSharp7.cs:135:21:135:21 | 2 |
+| CSharp7.cs:137:29:137:38 | (...) => ... | CSharp7.cs:137:34:137:38 | ... + ... |
+| CSharp7.cs:139:9:139:51 | f6 | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
+| CSharp7.cs:141:9:141:31 | f7 | CSharp7.cs:141:26:141:30 | call to local function f6 |
+| CSharp7.cs:145:13:145:35 | f9 | CSharp7.cs:145:30:145:34 | call to local function f7 |
+| CSharp7.cs:151:13:151:26 | f9 | CSharp7.cs:151:25:151:25 | 0 |
+| CSharp7.cs:159:9:159:24 | f | CSharp7.cs:159:23:159:23 | 1 |
+| CSharp7.cs:160:9:160:25 | g | CSharp7.cs:160:24:160:24 | access to parameter t |
+| CSharp7.cs:164:13:164:43 | f2 | CSharp7.cs:164:37:164:42 | call to local function f |
+| CSharp7.cs:176:9:176:40 | f | CSharp7.cs:176:31:176:39 | ... + ... |
+| CSharp7.cs:177:9:177:32 | g | CSharp7.cs:177:31:177:31 | access to parameter s |
+| CSharp7.cs:283:32:283:61 | (...) => ... | CSharp7.cs:283:40:283:61 | (..., ...) |
diff --git a/csharp/ql/test/library-tests/csharp7/ForEach.expected b/csharp/ql/test/library-tests/csharp7/ForEach.expected
index d0699faabf0..bba5443287d 100644
--- a/csharp/ql/test/library-tests/csharp7/ForEach.expected
+++ b/csharp/ql/test/library-tests/csharp7/ForEach.expected
@@ -1,6 +1,6 @@
-| CSharp7.cs:287:9:287:47 | foreach (... ... in ...) ... | 0 | CSharp7.cs:287:23:287:23 | Int32 a | CSharp7.cs:287:23:287:23 | a | CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:287:45:287:47 | {...} |
-| CSharp7.cs:287:9:287:47 | foreach (... ... in ...) ... | 1 | CSharp7.cs:287:33:287:33 | String b | CSharp7.cs:287:33:287:33 | b | CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:287:45:287:47 | {...} |
-| CSharp7.cs:289:9:289:44 | foreach (... ... in ...) ... | 0 | CSharp7.cs:289:23:289:23 | Int32 a | CSharp7.cs:289:23:289:23 | a | CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:289:42:289:44 | {...} |
-| CSharp7.cs:289:9:289:44 | foreach (... ... in ...) ... | 1 | CSharp7.cs:289:30:289:30 | String b | CSharp7.cs:289:30:289:30 | b | CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:289:42:289:44 | {...} |
-| CSharp7.cs:291:9:291:40 | foreach (... ... in ...) ... | 0 | CSharp7.cs:291:23:291:23 | Int32 a | CSharp7.cs:291:23:291:23 | a | CSharp7.cs:291:32:291:35 | access to local variable list | CSharp7.cs:291:38:291:40 | {...} |
-| CSharp7.cs:291:9:291:40 | foreach (... ... in ...) ... | 1 | CSharp7.cs:291:26:291:26 | String b | CSharp7.cs:291:26:291:26 | b | CSharp7.cs:291:32:291:35 | access to local variable list | CSharp7.cs:291:38:291:40 | {...} |
+| CSharp7.cs:285:9:285:47 | foreach (... ... in ...) ... | 0 | CSharp7.cs:285:23:285:23 | Int32 a | CSharp7.cs:285:23:285:23 | a | CSharp7.cs:285:39:285:42 | access to local variable list | CSharp7.cs:285:45:285:47 | {...} |
+| CSharp7.cs:285:9:285:47 | foreach (... ... in ...) ... | 1 | CSharp7.cs:285:33:285:33 | String b | CSharp7.cs:285:33:285:33 | b | CSharp7.cs:285:39:285:42 | access to local variable list | CSharp7.cs:285:45:285:47 | {...} |
+| CSharp7.cs:287:9:287:44 | foreach (... ... in ...) ... | 0 | CSharp7.cs:287:23:287:23 | Int32 a | CSharp7.cs:287:23:287:23 | a | CSharp7.cs:287:36:287:39 | access to local variable list | CSharp7.cs:287:42:287:44 | {...} |
+| CSharp7.cs:287:9:287:44 | foreach (... ... in ...) ... | 1 | CSharp7.cs:287:30:287:30 | String b | CSharp7.cs:287:30:287:30 | b | CSharp7.cs:287:36:287:39 | access to local variable list | CSharp7.cs:287:42:287:44 | {...} |
+| CSharp7.cs:289:9:289:40 | foreach (... ... in ...) ... | 0 | CSharp7.cs:289:23:289:23 | Int32 a | CSharp7.cs:289:23:289:23 | a | CSharp7.cs:289:32:289:35 | access to local variable list | CSharp7.cs:289:38:289:40 | {...} |
+| CSharp7.cs:289:9:289:40 | foreach (... ... in ...) ... | 1 | CSharp7.cs:289:26:289:26 | String b | CSharp7.cs:289:26:289:26 | b | CSharp7.cs:289:32:289:35 | access to local variable list | CSharp7.cs:289:38:289:40 | {...} |
diff --git a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected
index 1c058bc57f8..68c4963db45 100644
--- a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected
+++ b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected
@@ -1,40 +1,40 @@
edges
-| CSharp7.cs:41:9:41:21 | SSA def(x) : String | CSharp7.cs:51:22:51:23 | SSA def(t1) : String |
-| CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:41:9:41:21 | SSA def(x) : String |
-| CSharp7.cs:51:22:51:23 | SSA def(t1) : String | CSharp7.cs:53:18:53:19 | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:30:57:31 | SSA def(t4) : String |
-| CSharp7.cs:57:30:57:31 | SSA def(t4) : String | CSharp7.cs:58:18:58:19 | access to local variable t4 |
-| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String |
-| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String |
-| CSharp7.cs:92:20:92:27 | access to field Item1 : String | CSharp7.cs:92:18:92:28 | call to method I |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:23:183:25 | access to local variable src : String |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:184:23:184:25 | access to local variable src : String |
-| CSharp7.cs:183:23:183:25 | access to local variable src : String | CSharp7.cs:183:21:183:26 | call to local function g |
-| CSharp7.cs:184:23:184:25 | access to local variable src : String | CSharp7.cs:184:21:184:26 | call to local function h |
+| CSharp7.cs:39:9:39:21 | SSA def(x) : String | CSharp7.cs:49:22:49:23 | SSA def(t1) : String |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:39:9:39:21 | SSA def(x) : String |
+| CSharp7.cs:49:22:49:23 | SSA def(t1) : String | CSharp7.cs:51:18:51:19 | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:55:30:55:31 | SSA def(t4) : String |
+| CSharp7.cs:55:30:55:31 | SSA def(t4) : String | CSharp7.cs:56:18:56:19 | access to local variable t4 |
+| CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String | CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String |
+| CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:90:20:90:27 | access to field Item1 : String |
+| CSharp7.cs:90:20:90:27 | access to field Item1 : String | CSharp7.cs:90:18:90:28 | call to method I |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:181:23:181:25 | access to local variable src : String |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:182:23:182:25 | access to local variable src : String |
+| CSharp7.cs:181:23:181:25 | access to local variable src : String | CSharp7.cs:181:21:181:26 | call to local function g |
+| CSharp7.cs:182:23:182:25 | access to local variable src : String | CSharp7.cs:182:21:182:26 | call to local function h |
nodes
-| CSharp7.cs:41:9:41:21 | SSA def(x) : String | semmle.label | SSA def(x) : String |
-| CSharp7.cs:41:13:41:21 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:51:22:51:23 | SSA def(t1) : String | semmle.label | SSA def(t1) : String |
-| CSharp7.cs:53:18:53:19 | access to local variable t1 | semmle.label | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:57:30:57:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String |
-| CSharp7.cs:58:18:58:19 | access to local variable t4 | semmle.label | access to local variable t4 |
-| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:92:18:92:28 | call to method I | semmle.label | call to method I |
-| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String |
-| CSharp7.cs:92:20:92:27 | access to field Item1 : String | semmle.label | access to field Item1 : String |
-| CSharp7.cs:177:22:177:30 | "tainted" | semmle.label | "tainted" |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:183:21:183:26 | call to local function g | semmle.label | call to local function g |
-| CSharp7.cs:183:23:183:25 | access to local variable src : String | semmle.label | access to local variable src : String |
-| CSharp7.cs:184:21:184:26 | call to local function h | semmle.label | call to local function h |
-| CSharp7.cs:184:23:184:25 | access to local variable src : String | semmle.label | access to local variable src : String |
+| CSharp7.cs:39:9:39:21 | SSA def(x) : String | semmle.label | SSA def(x) : String |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:49:22:49:23 | SSA def(t1) : String | semmle.label | SSA def(t1) : String |
+| CSharp7.cs:51:18:51:19 | access to local variable t1 | semmle.label | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:55:30:55:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String |
+| CSharp7.cs:56:18:56:19 | access to local variable t4 | semmle.label | access to local variable t4 |
+| CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:90:18:90:28 | call to method I | semmle.label | call to method I |
+| CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String |
+| CSharp7.cs:90:20:90:27 | access to field Item1 : String | semmle.label | access to field Item1 : String |
+| CSharp7.cs:175:22:175:30 | "tainted" | semmle.label | "tainted" |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:181:21:181:26 | call to local function g | semmle.label | call to local function g |
+| CSharp7.cs:181:23:181:25 | access to local variable src : String | semmle.label | access to local variable src : String |
+| CSharp7.cs:182:21:182:26 | call to local function h | semmle.label | call to local function h |
+| CSharp7.cs:182:23:182:25 | access to local variable src : String | semmle.label | access to local variable src : String |
#select
-| CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:53:18:53:19 | access to local variable t1 | $@ | CSharp7.cs:53:18:53:19 | access to local variable t1 | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:58:18:58:19 | access to local variable t4 | $@ | CSharp7.cs:58:18:58:19 | access to local variable t4 | access to local variable t4 |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:92:18:92:28 | call to method I | $@ | CSharp7.cs:92:18:92:28 | call to method I | call to method I |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | $@ | CSharp7.cs:177:22:177:30 | "tainted" | "tainted" |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:21:183:26 | call to local function g | $@ | CSharp7.cs:183:21:183:26 | call to local function g | call to local function g |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:184:21:184:26 | call to local function h | $@ | CSharp7.cs:184:21:184:26 | call to local function h | call to local function h |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:51:18:51:19 | access to local variable t1 | $@ | CSharp7.cs:51:18:51:19 | access to local variable t1 | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:56:18:56:19 | access to local variable t4 | $@ | CSharp7.cs:56:18:56:19 | access to local variable t4 | access to local variable t4 |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:90:18:90:28 | call to method I | $@ | CSharp7.cs:90:18:90:28 | call to method I | call to method I |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:22:175:30 | "tainted" | $@ | CSharp7.cs:175:22:175:30 | "tainted" | "tainted" |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:181:21:181:26 | call to local function g | $@ | CSharp7.cs:181:21:181:26 | call to local function g | call to local function g |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:182:21:182:26 | call to local function h | $@ | CSharp7.cs:182:21:182:26 | call to local function h | call to local function h |
diff --git a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected
index 905162f0bbb..26c34a6483d 100644
--- a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected
+++ b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected
@@ -1,45 +1,45 @@
edges
-| CSharp7.cs:41:9:41:21 | SSA def(x) : String | CSharp7.cs:51:22:51:23 | SSA def(t1) : String |
-| CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:41:9:41:21 | SSA def(x) : String |
-| CSharp7.cs:51:22:51:23 | SSA def(t1) : String | CSharp7.cs:53:18:53:19 | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:30:57:31 | SSA def(t4) : String |
-| CSharp7.cs:57:30:57:31 | SSA def(t4) : String | CSharp7.cs:58:18:58:19 | access to local variable t4 |
-| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String |
-| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String |
-| CSharp7.cs:92:20:92:27 | access to field Item1 : String | CSharp7.cs:92:18:92:28 | call to method I |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:182:23:182:25 | access to local variable src : String |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:23:183:25 | access to local variable src : String |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:184:23:184:25 | access to local variable src : String |
-| CSharp7.cs:182:23:182:25 | access to local variable src : String | CSharp7.cs:182:21:182:26 | call to local function f |
-| CSharp7.cs:183:23:183:25 | access to local variable src : String | CSharp7.cs:183:21:183:26 | call to local function g |
-| CSharp7.cs:184:23:184:25 | access to local variable src : String | CSharp7.cs:184:21:184:26 | call to local function h |
+| CSharp7.cs:39:9:39:21 | SSA def(x) : String | CSharp7.cs:49:22:49:23 | SSA def(t1) : String |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:39:9:39:21 | SSA def(x) : String |
+| CSharp7.cs:49:22:49:23 | SSA def(t1) : String | CSharp7.cs:51:18:51:19 | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:55:30:55:31 | SSA def(t4) : String |
+| CSharp7.cs:55:30:55:31 | SSA def(t4) : String | CSharp7.cs:56:18:56:19 | access to local variable t4 |
+| CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String | CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String |
+| CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:90:20:90:27 | access to field Item1 : String |
+| CSharp7.cs:90:20:90:27 | access to field Item1 : String | CSharp7.cs:90:18:90:28 | call to method I |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:180:23:180:25 | access to local variable src : String |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:181:23:181:25 | access to local variable src : String |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:182:23:182:25 | access to local variable src : String |
+| CSharp7.cs:180:23:180:25 | access to local variable src : String | CSharp7.cs:180:21:180:26 | call to local function f |
+| CSharp7.cs:181:23:181:25 | access to local variable src : String | CSharp7.cs:181:21:181:26 | call to local function g |
+| CSharp7.cs:182:23:182:25 | access to local variable src : String | CSharp7.cs:182:21:182:26 | call to local function h |
nodes
-| CSharp7.cs:41:9:41:21 | SSA def(x) : String | semmle.label | SSA def(x) : String |
-| CSharp7.cs:41:13:41:21 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:51:22:51:23 | SSA def(t1) : String | semmle.label | SSA def(t1) : String |
-| CSharp7.cs:53:18:53:19 | access to local variable t1 | semmle.label | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:57:30:57:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String |
-| CSharp7.cs:58:18:58:19 | access to local variable t4 | semmle.label | access to local variable t4 |
-| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:92:18:92:28 | call to method I | semmle.label | call to method I |
-| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String |
-| CSharp7.cs:92:20:92:27 | access to field Item1 : String | semmle.label | access to field Item1 : String |
-| CSharp7.cs:177:22:177:30 | "tainted" | semmle.label | "tainted" |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | semmle.label | "tainted" : String |
-| CSharp7.cs:182:21:182:26 | call to local function f | semmle.label | call to local function f |
+| CSharp7.cs:39:9:39:21 | SSA def(x) : String | semmle.label | SSA def(x) : String |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:49:22:49:23 | SSA def(t1) : String | semmle.label | SSA def(t1) : String |
+| CSharp7.cs:51:18:51:19 | access to local variable t1 | semmle.label | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:55:30:55:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String |
+| CSharp7.cs:56:18:56:19 | access to local variable t4 | semmle.label | access to local variable t4 |
+| CSharp7.cs:87:18:87:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:90:18:90:28 | call to method I | semmle.label | call to method I |
+| CSharp7.cs:90:20:90:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String |
+| CSharp7.cs:90:20:90:27 | access to field Item1 : String | semmle.label | access to field Item1 : String |
+| CSharp7.cs:175:22:175:30 | "tainted" | semmle.label | "tainted" |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | semmle.label | "tainted" : String |
+| CSharp7.cs:180:21:180:26 | call to local function f | semmle.label | call to local function f |
+| CSharp7.cs:180:23:180:25 | access to local variable src : String | semmle.label | access to local variable src : String |
+| CSharp7.cs:181:21:181:26 | call to local function g | semmle.label | call to local function g |
+| CSharp7.cs:181:23:181:25 | access to local variable src : String | semmle.label | access to local variable src : String |
+| CSharp7.cs:182:21:182:26 | call to local function h | semmle.label | call to local function h |
| CSharp7.cs:182:23:182:25 | access to local variable src : String | semmle.label | access to local variable src : String |
-| CSharp7.cs:183:21:183:26 | call to local function g | semmle.label | call to local function g |
-| CSharp7.cs:183:23:183:25 | access to local variable src : String | semmle.label | access to local variable src : String |
-| CSharp7.cs:184:21:184:26 | call to local function h | semmle.label | call to local function h |
-| CSharp7.cs:184:23:184:25 | access to local variable src : String | semmle.label | access to local variable src : String |
#select
-| CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:41:13:41:21 | "tainted" : String | CSharp7.cs:53:18:53:19 | access to local variable t1 | $@ | CSharp7.cs:53:18:53:19 | access to local variable t1 | access to local variable t1 |
-| CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:58:18:58:19 | access to local variable t4 | $@ | CSharp7.cs:58:18:58:19 | access to local variable t4 | access to local variable t4 |
-| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:92:18:92:28 | call to method I | $@ | CSharp7.cs:92:18:92:28 | call to method I | call to method I |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:22:177:30 | "tainted" | $@ | CSharp7.cs:177:22:177:30 | "tainted" | "tainted" |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:182:21:182:26 | call to local function f | $@ | CSharp7.cs:182:21:182:26 | call to local function f | call to local function f |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:21:183:26 | call to local function g | $@ | CSharp7.cs:183:21:183:26 | call to local function g | call to local function g |
-| CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:184:21:184:26 | call to local function h | $@ | CSharp7.cs:184:21:184:26 | call to local function h | call to local function h |
+| CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:39:13:39:21 | "tainted" : String | CSharp7.cs:51:18:51:19 | access to local variable t1 | $@ | CSharp7.cs:51:18:51:19 | access to local variable t1 | access to local variable t1 |
+| CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:55:11:55:19 | "tainted" : String | CSharp7.cs:56:18:56:19 | access to local variable t4 | $@ | CSharp7.cs:56:18:56:19 | access to local variable t4 | access to local variable t4 |
+| CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:87:19:87:27 | "tainted" : String | CSharp7.cs:90:18:90:28 | call to method I | $@ | CSharp7.cs:90:18:90:28 | call to method I | call to method I |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:22:175:30 | "tainted" | $@ | CSharp7.cs:175:22:175:30 | "tainted" | "tainted" |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:180:21:180:26 | call to local function f | $@ | CSharp7.cs:180:21:180:26 | call to local function f | call to local function f |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:181:21:181:26 | call to local function g | $@ | CSharp7.cs:181:21:181:26 | call to local function g | call to local function g |
+| CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:175:22:175:30 | "tainted" : String | CSharp7.cs:182:21:182:26 | call to local function h | $@ | CSharp7.cs:182:21:182:26 | call to local function h | call to local function h |
diff --git a/csharp/ql/test/library-tests/csharp7/IsFlow.expected b/csharp/ql/test/library-tests/csharp7/IsFlow.expected
index 18b1fa2615f..b3e28352845 100644
--- a/csharp/ql/test/library-tests/csharp7/IsFlow.expected
+++ b/csharp/ql/test/library-tests/csharp7/IsFlow.expected
@@ -1,75 +1,75 @@
-| CSharp7.cs:232:10:232:13 | exit Test (normal) | CSharp7.cs:232:10:232:13 | exit Test | semmle.label | successor |
-| CSharp7.cs:250:9:276:9 | switch (...) {...} | CSharp7.cs:250:17:250:17 | access to local variable o | semmle.label | successor |
-| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:252:13:252:23 | case ...: | semmle.label | successor |
-| CSharp7.cs:252:13:252:23 | case ...: | CSharp7.cs:252:18:252:22 | "xyz" | semmle.label | successor |
-| CSharp7.cs:252:18:252:22 | "xyz" | CSharp7.cs:253:17:253:22 | break; | semmle.label | match |
-| CSharp7.cs:252:18:252:22 | "xyz" | CSharp7.cs:254:13:254:31 | case ...: | semmle.label | no-match |
-| CSharp7.cs:253:17:253:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:254:13:254:31 | case ...: | CSharp7.cs:254:18:254:19 | "" | semmle.label | successor |
-| CSharp7.cs:254:18:254:19 | "" | CSharp7.cs:254:26:254:26 | 1 | semmle.label | match |
-| CSharp7.cs:254:18:254:19 | "" | CSharp7.cs:256:13:256:41 | case ...: | semmle.label | no-match |
-| CSharp7.cs:254:26:254:26 | 1 | CSharp7.cs:254:30:254:30 | 2 | semmle.label | successor |
-| CSharp7.cs:254:26:254:30 | ... < ... | CSharp7.cs:255:17:255:22 | break; | semmle.label | true |
-| CSharp7.cs:254:30:254:30 | 2 | CSharp7.cs:254:26:254:30 | ... < ... | semmle.label | successor |
-| CSharp7.cs:255:17:255:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:256:13:256:41 | case ...: | CSharp7.cs:256:18:256:20 | "x" | semmle.label | successor |
-| CSharp7.cs:256:18:256:20 | "x" | CSharp7.cs:256:27:256:27 | access to local variable o | semmle.label | match |
-| CSharp7.cs:256:18:256:20 | "x" | CSharp7.cs:259:13:259:36 | case ...: | semmle.label | no-match |
-| CSharp7.cs:256:27:256:27 | access to local variable o | CSharp7.cs:256:32:256:40 | String s4 | semmle.label | successor |
-| CSharp7.cs:256:27:256:40 | [false] ... is ... | CSharp7.cs:259:13:259:36 | case ...: | semmle.label | false |
-| CSharp7.cs:256:27:256:40 | [true] ... is ... | CSharp7.cs:257:17:257:45 | ...; | semmle.label | true |
-| CSharp7.cs:256:32:256:40 | String s4 | CSharp7.cs:256:27:256:40 | [false] ... is ... | semmle.label | no-match |
-| CSharp7.cs:256:32:256:40 | String s4 | CSharp7.cs:256:27:256:40 | [true] ... is ... | semmle.label | match |
-| CSharp7.cs:257:17:257:44 | call to method WriteLine | CSharp7.cs:258:17:258:22 | break; | semmle.label | successor |
-| CSharp7.cs:257:17:257:45 | ...; | CSharp7.cs:257:37:257:38 | "x " | semmle.label | successor |
-| CSharp7.cs:257:35:257:43 | $"..." | CSharp7.cs:257:17:257:44 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:40:257:41 | access to local variable s4 | semmle.label | successor |
-| CSharp7.cs:257:40:257:41 | access to local variable s4 | CSharp7.cs:257:35:257:43 | $"..." | semmle.label | successor |
-| CSharp7.cs:258:17:258:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:18:259:23 | Int32 i2 | semmle.label | successor |
-| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:259:30:259:31 | access to local variable i2 | semmle.label | match |
-| CSharp7.cs:259:18:259:23 | Int32 i2 | CSharp7.cs:262:13:262:24 | case ...: | semmle.label | no-match |
-| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:259:35:259:35 | 0 | semmle.label | successor |
-| CSharp7.cs:259:30:259:35 | ... > ... | CSharp7.cs:260:17:260:52 | ...; | semmle.label | true |
-| CSharp7.cs:259:30:259:35 | ... > ... | CSharp7.cs:262:13:262:24 | case ...: | semmle.label | false |
-| CSharp7.cs:259:35:259:35 | 0 | CSharp7.cs:259:30:259:35 | ... > ... | semmle.label | successor |
-| CSharp7.cs:260:17:260:51 | call to method WriteLine | CSharp7.cs:261:17:261:22 | break; | semmle.label | successor |
-| CSharp7.cs:260:17:260:52 | ...; | CSharp7.cs:260:37:260:45 | "positive " | semmle.label | successor |
-| CSharp7.cs:260:35:260:50 | $"..." | CSharp7.cs:260:17:260:51 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:47:260:48 | access to local variable i2 | semmle.label | successor |
-| CSharp7.cs:260:47:260:48 | access to local variable i2 | CSharp7.cs:260:35:260:50 | $"..." | semmle.label | successor |
-| CSharp7.cs:261:17:261:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:262:13:262:24 | case ...: | CSharp7.cs:262:18:262:23 | Int32 i3 | semmle.label | successor |
-| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:263:17:263:47 | ...; | semmle.label | match |
-| CSharp7.cs:262:18:262:23 | Int32 i3 | CSharp7.cs:265:13:265:27 | case ...: | semmle.label | no-match |
-| CSharp7.cs:263:17:263:46 | call to method WriteLine | CSharp7.cs:264:17:264:22 | break; | semmle.label | successor |
-| CSharp7.cs:263:17:263:47 | ...; | CSharp7.cs:263:37:263:40 | "int " | semmle.label | successor |
-| CSharp7.cs:263:35:263:45 | $"..." | CSharp7.cs:263:17:263:46 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:42:263:43 | access to local variable i3 | semmle.label | successor |
-| CSharp7.cs:263:42:263:43 | access to local variable i3 | CSharp7.cs:263:35:263:45 | $"..." | semmle.label | successor |
-| CSharp7.cs:264:17:264:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:265:13:265:27 | case ...: | CSharp7.cs:265:18:265:26 | String s2 | semmle.label | successor |
-| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:266:17:266:50 | ...; | semmle.label | match |
-| CSharp7.cs:265:18:265:26 | String s2 | CSharp7.cs:268:13:268:26 | case ...: | semmle.label | no-match |
-| CSharp7.cs:266:17:266:49 | call to method WriteLine | CSharp7.cs:267:17:267:22 | break; | semmle.label | successor |
-| CSharp7.cs:266:17:266:50 | ...; | CSharp7.cs:266:37:266:43 | "string " | semmle.label | successor |
-| CSharp7.cs:266:35:266:48 | $"..." | CSharp7.cs:266:17:266:49 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:45:266:46 | access to local variable s2 | semmle.label | successor |
-| CSharp7.cs:266:45:266:46 | access to local variable s2 | CSharp7.cs:266:35:266:48 | $"..." | semmle.label | successor |
-| CSharp7.cs:267:17:267:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:268:13:268:26 | case ...: | CSharp7.cs:268:18:268:23 | access to type Double | semmle.label | successor |
-| CSharp7.cs:268:18:268:23 | access to type Double | CSharp7.cs:269:17:269:44 | ...; | semmle.label | match |
-| CSharp7.cs:268:18:268:23 | access to type Double | CSharp7.cs:271:13:271:24 | case ...: | semmle.label | no-match |
-| CSharp7.cs:269:17:269:43 | call to method WriteLine | CSharp7.cs:270:17:270:22 | break; | semmle.label | successor |
-| CSharp7.cs:269:17:269:44 | ...; | CSharp7.cs:269:35:269:42 | "Double" | semmle.label | successor |
-| CSharp7.cs:269:35:269:42 | "Double" | CSharp7.cs:269:17:269:43 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:270:17:270:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:271:13:271:24 | case ...: | CSharp7.cs:271:18:271:23 | Object v2 | semmle.label | successor |
-| CSharp7.cs:271:18:271:23 | Object v2 | CSharp7.cs:272:17:272:22 | break; | semmle.label | match |
-| CSharp7.cs:271:18:271:23 | Object v2 | CSharp7.cs:273:13:273:20 | default: | semmle.label | no-match |
-| CSharp7.cs:272:17:272:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
-| CSharp7.cs:273:13:273:20 | default: | CSharp7.cs:274:17:274:52 | ...; | semmle.label | successor |
-| CSharp7.cs:274:17:274:51 | call to method WriteLine | CSharp7.cs:275:17:275:22 | break; | semmle.label | successor |
-| CSharp7.cs:274:17:274:52 | ...; | CSharp7.cs:274:35:274:50 | "Something else" | semmle.label | successor |
-| CSharp7.cs:274:35:274:50 | "Something else" | CSharp7.cs:274:17:274:51 | call to method WriteLine | semmle.label | successor |
-| CSharp7.cs:275:17:275:22 | break; | CSharp7.cs:232:10:232:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:230:10:230:13 | exit Test (normal) | CSharp7.cs:230:10:230:13 | exit Test | semmle.label | successor |
+| CSharp7.cs:248:9:274:9 | switch (...) {...} | CSharp7.cs:248:17:248:17 | access to local variable o | semmle.label | successor |
+| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:250:13:250:23 | case ...: | semmle.label | successor |
+| CSharp7.cs:250:13:250:23 | case ...: | CSharp7.cs:250:18:250:22 | "xyz" | semmle.label | successor |
+| CSharp7.cs:250:18:250:22 | "xyz" | CSharp7.cs:251:17:251:22 | break; | semmle.label | match |
+| CSharp7.cs:250:18:250:22 | "xyz" | CSharp7.cs:252:13:252:31 | case ...: | semmle.label | no-match |
+| CSharp7.cs:251:17:251:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:252:13:252:31 | case ...: | CSharp7.cs:252:18:252:19 | "" | semmle.label | successor |
+| CSharp7.cs:252:18:252:19 | "" | CSharp7.cs:252:26:252:26 | 1 | semmle.label | match |
+| CSharp7.cs:252:18:252:19 | "" | CSharp7.cs:254:13:254:41 | case ...: | semmle.label | no-match |
+| CSharp7.cs:252:26:252:26 | 1 | CSharp7.cs:252:30:252:30 | 2 | semmle.label | successor |
+| CSharp7.cs:252:26:252:30 | ... < ... | CSharp7.cs:253:17:253:22 | break; | semmle.label | true |
+| CSharp7.cs:252:30:252:30 | 2 | CSharp7.cs:252:26:252:30 | ... < ... | semmle.label | successor |
+| CSharp7.cs:253:17:253:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:254:13:254:41 | case ...: | CSharp7.cs:254:18:254:20 | "x" | semmle.label | successor |
+| CSharp7.cs:254:18:254:20 | "x" | CSharp7.cs:254:27:254:27 | access to local variable o | semmle.label | match |
+| CSharp7.cs:254:18:254:20 | "x" | CSharp7.cs:257:13:257:36 | case ...: | semmle.label | no-match |
+| CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | String s4 | semmle.label | successor |
+| CSharp7.cs:254:27:254:40 | [false] ... is ... | CSharp7.cs:257:13:257:36 | case ...: | semmle.label | false |
+| CSharp7.cs:254:27:254:40 | [true] ... is ... | CSharp7.cs:255:17:255:45 | ...; | semmle.label | true |
+| CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:254:27:254:40 | [false] ... is ... | semmle.label | no-match |
+| CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:254:27:254:40 | [true] ... is ... | semmle.label | match |
+| CSharp7.cs:255:17:255:44 | call to method WriteLine | CSharp7.cs:256:17:256:22 | break; | semmle.label | successor |
+| CSharp7.cs:255:17:255:45 | ...; | CSharp7.cs:255:37:255:38 | "x " | semmle.label | successor |
+| CSharp7.cs:255:35:255:43 | $"..." | CSharp7.cs:255:17:255:44 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:40:255:41 | access to local variable s4 | semmle.label | successor |
+| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:35:255:43 | $"..." | semmle.label | successor |
+| CSharp7.cs:256:17:256:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:257:13:257:36 | case ...: | CSharp7.cs:257:18:257:23 | Int32 i2 | semmle.label | successor |
+| CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:257:30:257:31 | access to local variable i2 | semmle.label | match |
+| CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:260:13:260:24 | case ...: | semmle.label | no-match |
+| CSharp7.cs:257:30:257:31 | access to local variable i2 | CSharp7.cs:257:35:257:35 | 0 | semmle.label | successor |
+| CSharp7.cs:257:30:257:35 | ... > ... | CSharp7.cs:258:17:258:52 | ...; | semmle.label | true |
+| CSharp7.cs:257:30:257:35 | ... > ... | CSharp7.cs:260:13:260:24 | case ...: | semmle.label | false |
+| CSharp7.cs:257:35:257:35 | 0 | CSharp7.cs:257:30:257:35 | ... > ... | semmle.label | successor |
+| CSharp7.cs:258:17:258:51 | call to method WriteLine | CSharp7.cs:259:17:259:22 | break; | semmle.label | successor |
+| CSharp7.cs:258:17:258:52 | ...; | CSharp7.cs:258:37:258:45 | "positive " | semmle.label | successor |
+| CSharp7.cs:258:35:258:50 | $"..." | CSharp7.cs:258:17:258:51 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:258:37:258:45 | "positive " | CSharp7.cs:258:47:258:48 | access to local variable i2 | semmle.label | successor |
+| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:35:258:50 | $"..." | semmle.label | successor |
+| CSharp7.cs:259:17:259:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:260:13:260:24 | case ...: | CSharp7.cs:260:18:260:23 | Int32 i3 | semmle.label | successor |
+| CSharp7.cs:260:18:260:23 | Int32 i3 | CSharp7.cs:261:17:261:47 | ...; | semmle.label | match |
+| CSharp7.cs:260:18:260:23 | Int32 i3 | CSharp7.cs:263:13:263:27 | case ...: | semmle.label | no-match |
+| CSharp7.cs:261:17:261:46 | call to method WriteLine | CSharp7.cs:262:17:262:22 | break; | semmle.label | successor |
+| CSharp7.cs:261:17:261:47 | ...; | CSharp7.cs:261:37:261:40 | "int " | semmle.label | successor |
+| CSharp7.cs:261:35:261:45 | $"..." | CSharp7.cs:261:17:261:46 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:261:37:261:40 | "int " | CSharp7.cs:261:42:261:43 | access to local variable i3 | semmle.label | successor |
+| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:35:261:45 | $"..." | semmle.label | successor |
+| CSharp7.cs:262:17:262:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:263:13:263:27 | case ...: | CSharp7.cs:263:18:263:26 | String s2 | semmle.label | successor |
+| CSharp7.cs:263:18:263:26 | String s2 | CSharp7.cs:264:17:264:50 | ...; | semmle.label | match |
+| CSharp7.cs:263:18:263:26 | String s2 | CSharp7.cs:266:13:266:26 | case ...: | semmle.label | no-match |
+| CSharp7.cs:264:17:264:49 | call to method WriteLine | CSharp7.cs:265:17:265:22 | break; | semmle.label | successor |
+| CSharp7.cs:264:17:264:50 | ...; | CSharp7.cs:264:37:264:43 | "string " | semmle.label | successor |
+| CSharp7.cs:264:35:264:48 | $"..." | CSharp7.cs:264:17:264:49 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:264:37:264:43 | "string " | CSharp7.cs:264:45:264:46 | access to local variable s2 | semmle.label | successor |
+| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:35:264:48 | $"..." | semmle.label | successor |
+| CSharp7.cs:265:17:265:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:266:13:266:26 | case ...: | CSharp7.cs:266:18:266:23 | access to type Double | semmle.label | successor |
+| CSharp7.cs:266:18:266:23 | access to type Double | CSharp7.cs:267:17:267:44 | ...; | semmle.label | match |
+| CSharp7.cs:266:18:266:23 | access to type Double | CSharp7.cs:269:13:269:24 | case ...: | semmle.label | no-match |
+| CSharp7.cs:267:17:267:43 | call to method WriteLine | CSharp7.cs:268:17:268:22 | break; | semmle.label | successor |
+| CSharp7.cs:267:17:267:44 | ...; | CSharp7.cs:267:35:267:42 | "Double" | semmle.label | successor |
+| CSharp7.cs:267:35:267:42 | "Double" | CSharp7.cs:267:17:267:43 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:268:17:268:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:269:13:269:24 | case ...: | CSharp7.cs:269:18:269:23 | Object v2 | semmle.label | successor |
+| CSharp7.cs:269:18:269:23 | Object v2 | CSharp7.cs:270:17:270:22 | break; | semmle.label | match |
+| CSharp7.cs:269:18:269:23 | Object v2 | CSharp7.cs:271:13:271:20 | default: | semmle.label | no-match |
+| CSharp7.cs:270:17:270:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
+| CSharp7.cs:271:13:271:20 | default: | CSharp7.cs:272:17:272:52 | ...; | semmle.label | successor |
+| CSharp7.cs:272:17:272:51 | call to method WriteLine | CSharp7.cs:273:17:273:22 | break; | semmle.label | successor |
+| CSharp7.cs:272:17:272:52 | ...; | CSharp7.cs:272:35:272:50 | "Something else" | semmle.label | successor |
+| CSharp7.cs:272:35:272:50 | "Something else" | CSharp7.cs:272:17:272:51 | call to method WriteLine | semmle.label | successor |
+| CSharp7.cs:273:17:273:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break |
diff --git a/csharp/ql/test/library-tests/csharp7/IsPatterns.expected b/csharp/ql/test/library-tests/csharp7/IsPatterns.expected
index d40737bd462..3efc7f7954f 100644
--- a/csharp/ql/test/library-tests/csharp7/IsPatterns.expected
+++ b/csharp/ql/test/library-tests/csharp7/IsPatterns.expected
@@ -1,5 +1,5 @@
-| CSharp7.cs:235:13:235:23 | ... is ... | Int32 | CSharp7.cs:235:18:235:23 | Int32 i1 | false |
-| CSharp7.cs:239:18:239:31 | ... is ... | String | CSharp7.cs:239:23:239:31 | String s1 | false |
-| CSharp7.cs:246:18:246:28 | ... is ... | Object | CSharp7.cs:246:23:246:28 | Object v1 | true |
-| CSharp7.cs:256:27:256:40 | ... is ... | String | CSharp7.cs:256:32:256:40 | String s4 | false |
-| CSharp7.cs:299:35:299:44 | ... is ... | Int32 | CSharp7.cs:299:40:299:44 | Int32 y | false |
+| CSharp7.cs:233:13:233:23 | ... is ... | Int32 | CSharp7.cs:233:18:233:23 | Int32 i1 | false |
+| CSharp7.cs:237:18:237:31 | ... is ... | String | CSharp7.cs:237:23:237:31 | String s1 | false |
+| CSharp7.cs:244:18:244:28 | ... is ... | Object | CSharp7.cs:244:23:244:28 | Object v1 | true |
+| CSharp7.cs:254:27:254:40 | ... is ... | String | CSharp7.cs:254:32:254:40 | String s4 | false |
+| CSharp7.cs:297:35:297:44 | ... is ... | Int32 | CSharp7.cs:297:40:297:44 | Int32 y | false |
diff --git a/csharp/ql/test/library-tests/csharp7/Literals.expected b/csharp/ql/test/library-tests/csharp7/Literals.expected
index cea351f0450..7514f43206f 100644
--- a/csharp/ql/test/library-tests/csharp7/Literals.expected
+++ b/csharp/ql/test/library-tests/csharp7/Literals.expected
@@ -1,3 +1,3 @@
-| CSharp7.cs:9:13:9:18 | 11 | 11 |
-| CSharp7.cs:10:13:10:19 | 123456 | 123456 |
-| CSharp7.cs:11:13:11:23 | 128 | 128 |
+| CSharp7.cs:7:13:7:18 | 11 | 11 |
+| CSharp7.cs:8:13:8:19 | 123456 | 123456 |
+| CSharp7.cs:9:13:9:23 | 128 | 128 |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected
index 2cf7be36a11..23e24a0e5e4 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionCallArguments.expected
@@ -1,14 +1,14 @@
-| CSharp7.cs:141:38:141:46 | call to local function f7 | 0 | CSharp7.cs:141:41:141:45 | ... - ... |
-| CSharp7.cs:143:26:143:30 | call to local function f6 | 0 | CSharp7.cs:143:29:143:29 | access to parameter x |
-| CSharp7.cs:147:30:147:34 | call to local function f7 | 0 | CSharp7.cs:147:33:147:33 | access to parameter x |
-| CSharp7.cs:148:20:148:24 | call to local function f9 | 0 | CSharp7.cs:148:23:148:23 | 1 |
-| CSharp7.cs:156:16:156:20 | call to local function f1 | 0 | CSharp7.cs:156:19:156:19 | 2 |
-| CSharp7.cs:168:20:168:23 | call to local function g | 0 | CSharp7.cs:168:22:168:22 | access to parameter u |
-| CSharp7.cs:171:9:171:15 | call to local function h | 0 | CSharp7.cs:171:11:171:11 | 0 |
-| CSharp7.cs:171:9:171:15 | call to local function h | 1 | CSharp7.cs:171:14:171:14 | 0 |
-| CSharp7.cs:172:9:172:19 | call to local function h | 0 | CSharp7.cs:172:11:172:12 | "" |
-| CSharp7.cs:172:9:172:19 | call to local function h | 1 | CSharp7.cs:172:15:172:18 | true |
-| CSharp7.cs:178:31:178:34 | call to local function g | 0 | CSharp7.cs:178:33:178:33 | access to parameter s |
-| CSharp7.cs:182:21:182:26 | call to local function f | 0 | CSharp7.cs:182:23:182:25 | access to local variable src |
-| CSharp7.cs:183:21:183:26 | call to local function g | 0 | CSharp7.cs:183:23:183:25 | access to local variable src |
-| CSharp7.cs:184:21:184:26 | call to local function h | 0 | CSharp7.cs:184:23:184:25 | access to local variable src |
+| CSharp7.cs:139:38:139:46 | call to local function f7 | 0 | CSharp7.cs:139:41:139:45 | ... - ... |
+| CSharp7.cs:141:26:141:30 | call to local function f6 | 0 | CSharp7.cs:141:29:141:29 | access to parameter x |
+| CSharp7.cs:145:30:145:34 | call to local function f7 | 0 | CSharp7.cs:145:33:145:33 | access to parameter x |
+| CSharp7.cs:146:20:146:24 | call to local function f9 | 0 | CSharp7.cs:146:23:146:23 | 1 |
+| CSharp7.cs:154:16:154:20 | call to local function f1 | 0 | CSharp7.cs:154:19:154:19 | 2 |
+| CSharp7.cs:166:20:166:23 | call to local function g | 0 | CSharp7.cs:166:22:166:22 | access to parameter u |
+| CSharp7.cs:169:9:169:15 | call to local function h | 0 | CSharp7.cs:169:11:169:11 | 0 |
+| CSharp7.cs:169:9:169:15 | call to local function h | 1 | CSharp7.cs:169:14:169:14 | 0 |
+| CSharp7.cs:170:9:170:19 | call to local function h | 0 | CSharp7.cs:170:11:170:12 | "" |
+| CSharp7.cs:170:9:170:19 | call to local function h | 1 | CSharp7.cs:170:15:170:18 | true |
+| CSharp7.cs:176:31:176:34 | call to local function g | 0 | CSharp7.cs:176:33:176:33 | access to parameter s |
+| CSharp7.cs:180:21:180:26 | call to local function f | 0 | CSharp7.cs:180:23:180:25 | access to local variable src |
+| CSharp7.cs:181:21:181:26 | call to local function g | 0 | CSharp7.cs:181:23:181:25 | access to local variable src |
+| CSharp7.cs:182:21:182:26 | call to local function h | 0 | CSharp7.cs:182:23:182:25 | access to local variable src |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected
index f465839b3cf..10a04a78d68 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected
@@ -1,14 +1,14 @@
-| CSharp7.cs:141:38:141:46 | call to local function f7 | CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:9:143:31 | f7 |
-| CSharp7.cs:143:26:143:30 | call to local function f6 | CSharp7.cs:141:9:141:51 | f6 | CSharp7.cs:141:9:141:51 | f6 |
-| CSharp7.cs:147:30:147:34 | call to local function f7 | CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:9:143:31 | f7 |
-| CSharp7.cs:148:20:148:24 | call to local function f9 | CSharp7.cs:147:13:147:35 | f9 | CSharp7.cs:147:13:147:35 | f9 |
-| CSharp7.cs:156:16:156:20 | call to local function f1 | CSharp7.cs:131:9:131:39 | f1 | CSharp7.cs:131:9:131:39 | f1 |
-| CSharp7.cs:166:37:166:42 | call to local function f | CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:9:161:24 | f |
-| CSharp7.cs:167:13:167:18 | call to local function f | CSharp7.cs:161:9:161:24 | f | CSharp7.cs:161:9:161:24 | f |
-| CSharp7.cs:168:20:168:23 | call to local function g | CSharp7.cs:162:9:162:25 | g | CSharp7.cs:162:9:162:25 | g |
-| CSharp7.cs:171:9:171:15 | call to local function h | CSharp7.cs:164:9:169:9 | h | CSharp7.cs:164:9:169:9 | h |
-| CSharp7.cs:172:9:172:19 | call to local function h | CSharp7.cs:164:9:169:9 | h | CSharp7.cs:164:9:169:9 | h |
-| CSharp7.cs:178:31:178:34 | call to local function g | CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:9:179:32 | g |
-| CSharp7.cs:182:21:182:26 | call to local function f | CSharp7.cs:178:9:178:40 | f | CSharp7.cs:178:9:178:40 | f |
-| CSharp7.cs:183:21:183:26 | call to local function g | CSharp7.cs:179:9:179:32 | g | CSharp7.cs:179:9:179:32 | g |
-| CSharp7.cs:184:21:184:26 | call to local function h | CSharp7.cs:180:9:180:40 | h | CSharp7.cs:180:9:180:40 | h |
+| CSharp7.cs:139:38:139:46 | call to local function f7 | CSharp7.cs:141:9:141:31 | f7 | CSharp7.cs:141:9:141:31 | f7 |
+| CSharp7.cs:141:26:141:30 | call to local function f6 | CSharp7.cs:139:9:139:51 | f6 | CSharp7.cs:139:9:139:51 | f6 |
+| CSharp7.cs:145:30:145:34 | call to local function f7 | CSharp7.cs:141:9:141:31 | f7 | CSharp7.cs:141:9:141:31 | f7 |
+| CSharp7.cs:146:20:146:24 | call to local function f9 | CSharp7.cs:145:13:145:35 | f9 | CSharp7.cs:145:13:145:35 | f9 |
+| CSharp7.cs:154:16:154:20 | call to local function f1 | CSharp7.cs:129:9:129:39 | f1 | CSharp7.cs:129:9:129:39 | f1 |
+| CSharp7.cs:164:37:164:42 | call to local function f | CSharp7.cs:159:9:159:24 | f | CSharp7.cs:159:9:159:24 | f |
+| CSharp7.cs:165:13:165:18 | call to local function f | CSharp7.cs:159:9:159:24 | f | CSharp7.cs:159:9:159:24 | f |
+| CSharp7.cs:166:20:166:23 | call to local function g | CSharp7.cs:160:9:160:25 | g | CSharp7.cs:160:9:160:25 | g |
+| CSharp7.cs:169:9:169:15 | call to local function h | CSharp7.cs:162:9:167:9 | h | CSharp7.cs:162:9:167:9 | h |
+| CSharp7.cs:170:9:170:19 | call to local function h | CSharp7.cs:162:9:167:9 | h | CSharp7.cs:162:9:167:9 | h |
+| CSharp7.cs:176:31:176:34 | call to local function g | CSharp7.cs:177:9:177:32 | g | CSharp7.cs:177:9:177:32 | g |
+| CSharp7.cs:180:21:180:26 | call to local function f | CSharp7.cs:176:9:176:40 | f | CSharp7.cs:176:9:176:40 | f |
+| CSharp7.cs:181:21:181:26 | call to local function g | CSharp7.cs:177:9:177:32 | g | CSharp7.cs:177:9:177:32 | g |
+| CSharp7.cs:182:21:182:26 | call to local function h | CSharp7.cs:178:9:178:40 | h | CSharp7.cs:178:9:178:40 | h |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected
index a9ae61c7b86..f5a1129298a 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected
@@ -1,20 +1,20 @@
-| CSharp7.cs:131:9:131:39 | f1 | 0 | CSharp7.cs:131:20:131:20 | x | Int32 |
-| CSharp7.cs:133:9:133:42 | f2 | 0 | CSharp7.cs:133:22:133:22 | t | T |
-| CSharp7.cs:133:9:133:42 | f2 | 1 | CSharp7.cs:133:27:133:27 | u | U |
-| CSharp7.cs:141:9:141:51 | f6 | 0 | CSharp7.cs:141:20:141:20 | x | Int32 |
-| CSharp7.cs:143:9:143:31 | f7 | 0 | CSharp7.cs:143:20:143:20 | x | Int32 |
-| CSharp7.cs:147:13:147:35 | f9 | 0 | CSharp7.cs:147:24:147:24 | x | Int32 |
-| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:18:162:18 | t | T |
-| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:18:162:18 | t | U |
-| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | Int32 |
-| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | String |
-| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:21:164:21 | t | T |
-| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | Boolean |
-| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | Int32 |
-| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:26:164:26 | u | U |
-| CSharp7.cs:166:13:166:43 | f2 | 0 | CSharp7.cs:166:25:166:25 | s | S |
-| CSharp7.cs:166:13:166:43 | f2 | 1 | CSharp7.cs:166:30:166:31 | _t | T |
-| CSharp7.cs:178:9:178:40 | f | 0 | CSharp7.cs:178:25:178:25 | s | String |
-| CSharp7.cs:179:9:179:32 | g | 0 | CSharp7.cs:179:25:179:25 | s | String |
-| CSharp7.cs:180:9:180:40 | h | 0 | CSharp7.cs:180:25:180:25 | s | String |
-| CSharp7.cs:206:9:206:47 | F3 | 0 | CSharp7.cs:206:28:206:28 | q | Int32 |
+| CSharp7.cs:129:9:129:39 | f1 | 0 | CSharp7.cs:129:20:129:20 | x | Int32 |
+| CSharp7.cs:131:9:131:42 | f2 | 0 | CSharp7.cs:131:22:131:22 | t | T |
+| CSharp7.cs:131:9:131:42 | f2 | 1 | CSharp7.cs:131:27:131:27 | u | U |
+| CSharp7.cs:139:9:139:51 | f6 | 0 | CSharp7.cs:139:20:139:20 | x | Int32 |
+| CSharp7.cs:141:9:141:31 | f7 | 0 | CSharp7.cs:141:20:141:20 | x | Int32 |
+| CSharp7.cs:145:13:145:35 | f9 | 0 | CSharp7.cs:145:24:145:24 | x | Int32 |
+| CSharp7.cs:160:9:160:25 | g | 0 | CSharp7.cs:160:18:160:18 | t | T |
+| CSharp7.cs:160:9:160:25 | g | 0 | CSharp7.cs:160:18:160:18 | t | U |
+| CSharp7.cs:162:9:167:9 | h | 0 | CSharp7.cs:162:21:162:21 | t | Int32 |
+| CSharp7.cs:162:9:167:9 | h | 0 | CSharp7.cs:162:21:162:21 | t | String |
+| CSharp7.cs:162:9:167:9 | h | 0 | CSharp7.cs:162:21:162:21 | t | T |
+| CSharp7.cs:162:9:167:9 | h | 1 | CSharp7.cs:162:26:162:26 | u | Boolean |
+| CSharp7.cs:162:9:167:9 | h | 1 | CSharp7.cs:162:26:162:26 | u | Int32 |
+| CSharp7.cs:162:9:167:9 | h | 1 | CSharp7.cs:162:26:162:26 | u | U |
+| CSharp7.cs:164:13:164:43 | f2 | 0 | CSharp7.cs:164:25:164:25 | s | S |
+| CSharp7.cs:164:13:164:43 | f2 | 1 | CSharp7.cs:164:30:164:31 | _t | T |
+| CSharp7.cs:176:9:176:40 | f | 0 | CSharp7.cs:176:25:176:25 | s | String |
+| CSharp7.cs:177:9:177:32 | g | 0 | CSharp7.cs:177:25:177:25 | s | String |
+| CSharp7.cs:178:9:178:40 | h | 0 | CSharp7.cs:178:25:178:25 | s | String |
+| CSharp7.cs:204:9:204:47 | F3 | 0 | CSharp7.cs:204:28:204:28 | q | Int32 |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected
index 748bef67d7e..f7dab69fba8 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected
@@ -1,16 +1,16 @@
-| CSharp7.cs:131:9:131:39 | f1(...) | CSharp7.cs:131:9:131:39 | f1 |
-| CSharp7.cs:133:9:133:42 | f2(...) | CSharp7.cs:133:9:133:42 | f2 |
-| CSharp7.cs:137:9:137:22 | f3(...) | CSharp7.cs:137:9:137:22 | f3 |
-| CSharp7.cs:141:9:141:51 | f6(...) | CSharp7.cs:141:9:141:51 | f6 |
-| CSharp7.cs:143:9:143:31 | f7(...) | CSharp7.cs:143:9:143:31 | f7 |
-| CSharp7.cs:145:9:149:9 | f8(...) | CSharp7.cs:145:9:149:9 | f8 |
-| CSharp7.cs:147:13:147:35 | f9(...) | CSharp7.cs:147:13:147:35 | f9 |
-| CSharp7.cs:153:13:153:26 | f9(...) | CSharp7.cs:153:13:153:26 | f9 |
-| CSharp7.cs:161:9:161:24 | f(...) | CSharp7.cs:161:9:161:24 | f |
-| CSharp7.cs:162:9:162:25 | g(...) | CSharp7.cs:162:9:162:25 | g |
-| CSharp7.cs:164:9:169:9 | h(...) | CSharp7.cs:164:9:169:9 | h |
-| CSharp7.cs:166:13:166:43 | f2(...) | CSharp7.cs:166:13:166:43 | f2 |
-| CSharp7.cs:178:9:178:40 | f(...) | CSharp7.cs:178:9:178:40 | f |
-| CSharp7.cs:179:9:179:32 | g(...) | CSharp7.cs:179:9:179:32 | g |
-| CSharp7.cs:180:9:180:40 | h(...) | CSharp7.cs:180:9:180:40 | h |
-| CSharp7.cs:206:9:206:47 | F3(...) | CSharp7.cs:206:9:206:47 | F3 |
+| CSharp7.cs:129:9:129:39 | f1(...) | CSharp7.cs:129:9:129:39 | f1 |
+| CSharp7.cs:131:9:131:42 | f2(...) | CSharp7.cs:131:9:131:42 | f2 |
+| CSharp7.cs:135:9:135:22 | f3(...) | CSharp7.cs:135:9:135:22 | f3 |
+| CSharp7.cs:139:9:139:51 | f6(...) | CSharp7.cs:139:9:139:51 | f6 |
+| CSharp7.cs:141:9:141:31 | f7(...) | CSharp7.cs:141:9:141:31 | f7 |
+| CSharp7.cs:143:9:147:9 | f8(...) | CSharp7.cs:143:9:147:9 | f8 |
+| CSharp7.cs:145:13:145:35 | f9(...) | CSharp7.cs:145:13:145:35 | f9 |
+| CSharp7.cs:151:13:151:26 | f9(...) | CSharp7.cs:151:13:151:26 | f9 |
+| CSharp7.cs:159:9:159:24 | f(...) | CSharp7.cs:159:9:159:24 | f |
+| CSharp7.cs:160:9:160:25 | g(...) | CSharp7.cs:160:9:160:25 | g |
+| CSharp7.cs:162:9:167:9 | h(...) | CSharp7.cs:162:9:167:9 | h |
+| CSharp7.cs:164:13:164:43 | f2(...) | CSharp7.cs:164:13:164:43 | f2 |
+| CSharp7.cs:176:9:176:40 | f(...) | CSharp7.cs:176:9:176:40 | f |
+| CSharp7.cs:177:9:177:32 | g(...) | CSharp7.cs:177:9:177:32 | g |
+| CSharp7.cs:178:9:178:40 | h(...) | CSharp7.cs:178:9:178:40 | h |
+| CSharp7.cs:204:9:204:47 | F3(...) | CSharp7.cs:204:9:204:47 | F3 |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected
index 789895f434d..152fecaae09 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected
@@ -1,20 +1,20 @@
-| CSharp7.cs:131:9:131:39 | f1 | f1 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:131:9:131:39 | f1(...) | f1(int) |
-| CSharp7.cs:133:9:133:42 | f2 | f2 | T | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:133:9:133:42 | f2(...) | f2(T, U) |
-| CSharp7.cs:137:9:137:22 | f3 | f3 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:137:9:137:22 | f3(...) | f3() |
-| CSharp7.cs:141:9:141:51 | f6 | f6 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:141:9:141:51 | f6(...) | f6(int) |
-| CSharp7.cs:143:9:143:31 | f7 | f7 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:143:9:143:31 | f7(...) | f7(int) |
-| CSharp7.cs:145:9:149:9 | f8 | f8 | Int32 | CSharp7.cs:130:5:157:5 | {...} | CSharp7.cs:145:9:149:9 | f8(...) | f8() |
-| CSharp7.cs:147:13:147:35 | f9 | f9 | Int32 | CSharp7.cs:146:9:149:9 | {...} | CSharp7.cs:147:13:147:35 | f9(...) | f9(int) |
-| CSharp7.cs:153:13:153:26 | f9 | f9 | Int32 | CSharp7.cs:152:9:154:9 | {...} | CSharp7.cs:153:13:153:26 | f9(...) | f9() |
-| CSharp7.cs:161:9:161:24 | f | f | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:161:9:161:24 | f(...) | f() |
-| CSharp7.cs:161:9:161:24 | f | f | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:161:9:161:24 | f(...) | f() |
-| CSharp7.cs:162:9:162:25 | g | g | T | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:162:9:162:25 | g(...) | g(T) |
-| CSharp7.cs:162:9:162:25 | g | g | U | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:162:9:162:25 | g(...) | g(U) |
-| CSharp7.cs:164:9:169:9 | h | h | Boolean | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(string, bool) |
-| CSharp7.cs:164:9:169:9 | h | h | Int32 | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(int, int) |
-| CSharp7.cs:164:9:169:9 | h | h | U | CSharp7.cs:160:5:173:5 | {...} | CSharp7.cs:164:9:169:9 | h(...) | h(T, U) |
-| CSharp7.cs:166:13:166:43 | f2 | f2 | Int32 | CSharp7.cs:165:9:169:9 | {...} | CSharp7.cs:166:13:166:43 | f2(...) | f2(S, T) |
-| CSharp7.cs:178:9:178:40 | f | f | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:178:9:178:40 | f(...) | f(string) |
-| CSharp7.cs:179:9:179:32 | g | g | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:179:9:179:32 | g(...) | g(string) |
-| CSharp7.cs:180:9:180:40 | h | h | String | CSharp7.cs:176:5:185:5 | {...} | CSharp7.cs:180:9:180:40 | h(...) | h(string) |
-| CSharp7.cs:206:9:206:47 | F3 | F3 | Int32 | CSharp7.cs:205:5:208:5 | {...} | CSharp7.cs:206:9:206:47 | F3(...) | F3(ref int) |
+| CSharp7.cs:129:9:129:39 | f1 | f1 | Int32 | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:129:9:129:39 | f1(...) | f1(int) |
+| CSharp7.cs:131:9:131:42 | f2 | f2 | T | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:131:9:131:42 | f2(...) | f2(T, U) |
+| CSharp7.cs:135:9:135:22 | f3 | f3 | Int32 | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:135:9:135:22 | f3(...) | f3() |
+| CSharp7.cs:139:9:139:51 | f6 | f6 | Int32 | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:139:9:139:51 | f6(...) | f6(int) |
+| CSharp7.cs:141:9:141:31 | f7 | f7 | Int32 | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:141:9:141:31 | f7(...) | f7(int) |
+| CSharp7.cs:143:9:147:9 | f8 | f8 | Int32 | CSharp7.cs:128:5:155:5 | {...} | CSharp7.cs:143:9:147:9 | f8(...) | f8() |
+| CSharp7.cs:145:13:145:35 | f9 | f9 | Int32 | CSharp7.cs:144:9:147:9 | {...} | CSharp7.cs:145:13:145:35 | f9(...) | f9(int) |
+| CSharp7.cs:151:13:151:26 | f9 | f9 | Int32 | CSharp7.cs:150:9:152:9 | {...} | CSharp7.cs:151:13:151:26 | f9(...) | f9() |
+| CSharp7.cs:159:9:159:24 | f | f | Int32 | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:159:9:159:24 | f(...) | f() |
+| CSharp7.cs:159:9:159:24 | f | f | Int32 | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:159:9:159:24 | f(...) | f() |
+| CSharp7.cs:160:9:160:25 | g | g | T | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:160:9:160:25 | g(...) | g(T) |
+| CSharp7.cs:160:9:160:25 | g | g | U | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:160:9:160:25 | g(...) | g(U) |
+| CSharp7.cs:162:9:167:9 | h | h | Boolean | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:162:9:167:9 | h(...) | h(string, bool) |
+| CSharp7.cs:162:9:167:9 | h | h | Int32 | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:162:9:167:9 | h(...) | h(int, int) |
+| CSharp7.cs:162:9:167:9 | h | h | U | CSharp7.cs:158:5:171:5 | {...} | CSharp7.cs:162:9:167:9 | h(...) | h(T, U) |
+| CSharp7.cs:164:13:164:43 | f2 | f2 | Int32 | CSharp7.cs:163:9:167:9 | {...} | CSharp7.cs:164:13:164:43 | f2(...) | f2(S, T) |
+| CSharp7.cs:176:9:176:40 | f | f | String | CSharp7.cs:174:5:183:5 | {...} | CSharp7.cs:176:9:176:40 | f(...) | f(string) |
+| CSharp7.cs:177:9:177:32 | g | g | String | CSharp7.cs:174:5:183:5 | {...} | CSharp7.cs:177:9:177:32 | g(...) | g(string) |
+| CSharp7.cs:178:9:178:40 | h | h | String | CSharp7.cs:174:5:183:5 | {...} | CSharp7.cs:178:9:178:40 | h(...) | h(string) |
+| CSharp7.cs:204:9:204:47 | F3 | F3 | Int32 | CSharp7.cs:203:5:206:5 | {...} | CSharp7.cs:204:9:204:47 | F3(...) | F3(ref int) |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected
index 093a9ef0026..6091ed88d87 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected
@@ -1,224 +1,224 @@
-| CSharp7.cs:7:7:7:14 | this | CSharp7.cs:9:9:9:9 | this access |
-| CSharp7.cs:9:9:9:9 | [post] this access | CSharp7.cs:10:9:10:9 | this access |
-| CSharp7.cs:9:9:9:9 | this access | CSharp7.cs:10:9:10:9 | this access |
-| CSharp7.cs:10:9:10:9 | [post] this access | CSharp7.cs:11:9:11:9 | this access |
-| CSharp7.cs:10:9:10:9 | this access | CSharp7.cs:11:9:11:9 | this access |
-| CSharp7.cs:16:9:16:13 | [post] this access | CSharp7.cs:25:39:25:43 | this access |
-| CSharp7.cs:16:9:16:13 | this access | CSharp7.cs:25:39:25:43 | this access |
-| CSharp7.cs:17:9:17:11 | SSA entry def(this.field) | CSharp7.cs:17:18:17:22 | access to field field |
-| CSharp7.cs:17:9:17:11 | this | CSharp7.cs:17:18:17:22 | this access |
-| CSharp7.cs:21:9:21:11 | this | CSharp7.cs:21:16:21:20 | this access |
-| CSharp7.cs:22:9:22:11 | this | CSharp7.cs:22:16:22:20 | this access |
-| CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:24:22:28 | access to parameter value |
-| CSharp7.cs:25:5:25:27 | this | CSharp7.cs:16:9:16:13 | this access |
-| CSharp7.cs:26:6:26:28 | this | CSharp7.cs:26:35:26:39 | this access |
-| CSharp7.cs:31:19:31:19 | i | CSharp7.cs:33:16:33:16 | access to parameter i |
-| CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:16:33:20 | ... > ... |
-| CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:24:33:24 | access to parameter i |
-| CSharp7.cs:33:24:33:24 | access to parameter i | CSharp7.cs:33:16:33:59 | ... ? ... : ... |
-| CSharp7.cs:41:13:41:21 | "tainted" | CSharp7.cs:41:9:41:21 | SSA def(x) |
-| CSharp7.cs:44:19:44:19 | x | CSharp7.cs:46:13:46:13 | access to parameter x |
-| CSharp7.cs:46:13:46:13 | access to parameter x | CSharp7.cs:46:9:46:13 | SSA def(y) |
-| CSharp7.cs:49:10:49:10 | this | CSharp7.cs:51:9:51:24 | this access |
-| CSharp7.cs:51:9:51:24 | [post] this access | CSharp7.cs:52:9:52:21 | this access |
-| CSharp7.cs:51:9:51:24 | this access | CSharp7.cs:52:9:52:21 | this access |
-| CSharp7.cs:51:22:51:23 | SSA def(t1) | CSharp7.cs:53:18:53:19 | access to local variable t1 |
-| CSharp7.cs:52:9:52:21 | [post] this access | CSharp7.cs:54:9:54:17 | this access |
-| CSharp7.cs:52:9:52:21 | this access | CSharp7.cs:54:9:54:17 | this access |
-| CSharp7.cs:52:19:52:20 | SSA def(t2) | CSharp7.cs:56:14:56:15 | access to local variable t2 |
-| CSharp7.cs:54:9:54:17 | [post] this access | CSharp7.cs:57:9:57:32 | this access |
-| CSharp7.cs:54:9:54:17 | this access | CSharp7.cs:57:9:57:32 | this access |
-| CSharp7.cs:54:15:54:16 | SSA def(t1) | CSharp7.cs:55:14:55:15 | access to local variable t1 |
-| CSharp7.cs:57:30:57:31 | SSA def(t4) | CSharp7.cs:58:18:58:19 | access to local variable t4 |
-| CSharp7.cs:69:10:69:20 | this | CSharp7.cs:71:26:71:28 | this access |
-| CSharp7.cs:71:26:71:28 | [post] this access | CSharp7.cs:72:17:72:19 | this access |
-| CSharp7.cs:71:26:71:28 | call to method F | CSharp7.cs:71:9:71:22 | (..., ...) |
-| CSharp7.cs:71:26:71:28 | this access | CSharp7.cs:72:17:72:19 | this access |
-| CSharp7.cs:72:13:72:19 | SSA def(z) | CSharp7.cs:75:16:75:16 | access to local variable z |
-| CSharp7.cs:72:17:72:19 | [post] this access | CSharp7.cs:73:18:73:20 | this access |
-| CSharp7.cs:72:17:72:19 | call to method F | CSharp7.cs:72:13:72:19 | SSA def(z) |
-| CSharp7.cs:72:17:72:19 | this access | CSharp7.cs:73:18:73:20 | this access |
-| CSharp7.cs:73:18:73:20 | [post] this access | CSharp7.cs:74:13:74:15 | this access |
-| CSharp7.cs:73:18:73:20 | call to method F | CSharp7.cs:73:9:73:14 | (..., ...) |
-| CSharp7.cs:73:18:73:20 | this access | CSharp7.cs:74:13:74:15 | this access |
-| CSharp7.cs:75:16:75:16 | [post] access to local variable z | CSharp7.cs:77:39:77:39 | access to local variable z |
-| CSharp7.cs:75:16:75:16 | access to local variable z | CSharp7.cs:77:39:77:39 | access to local variable z |
-| CSharp7.cs:75:27:75:35 | (..., ...) | CSharp7.cs:75:9:75:23 | (..., ...) |
-| CSharp7.cs:76:9:76:32 | SSA def(x) | CSharp7.cs:79:27:79:27 | access to local variable x |
-| CSharp7.cs:76:18:76:32 | ... = ... | CSharp7.cs:76:9:76:14 | (..., ...) |
-| CSharp7.cs:76:27:76:32 | (..., ...) | CSharp7.cs:76:18:76:23 | (..., ...) |
-| CSharp7.cs:76:27:76:32 | (..., ...) | CSharp7.cs:76:18:76:32 | ... = ... |
-| CSharp7.cs:77:9:77:40 | SSA def(a) | CSharp7.cs:78:31:78:31 | access to local variable a |
-| CSharp7.cs:77:9:77:40 | SSA def(b) | CSharp7.cs:78:24:78:24 | access to local variable b |
-| CSharp7.cs:77:9:77:40 | SSA def(c) | CSharp7.cs:78:28:78:28 | access to local variable c |
-| CSharp7.cs:77:35:77:40 | (..., ...) | CSharp7.cs:77:9:77:31 | (..., ...) |
-| CSharp7.cs:77:36:77:36 | 1 | CSharp7.cs:77:9:77:40 | SSA def(a) |
-| CSharp7.cs:78:23:78:33 | (..., ...) | CSharp7.cs:78:9:78:19 | (..., ...) |
-| CSharp7.cs:79:22:79:28 | (..., ...) | CSharp7.cs:79:9:79:18 | (..., ...) |
-| CSharp7.cs:82:21:82:21 | x | CSharp7.cs:84:20:84:20 | access to parameter x |
-| CSharp7.cs:87:10:87:18 | this | CSharp7.cs:92:18:92:28 | this access |
-| CSharp7.cs:89:13:89:34 | SSA def(t1) | CSharp7.cs:90:28:90:29 | access to local variable t1 |
-| CSharp7.cs:89:13:89:34 | SSA qualifier def(t1.Item1) | CSharp7.cs:92:20:92:27 | access to field Item1 |
-| CSharp7.cs:89:18:89:34 | (..., ...) | CSharp7.cs:89:13:89:34 | SSA def(t1) |
-| CSharp7.cs:90:9:90:29 | SSA def(t3) | CSharp7.cs:91:18:91:19 | access to local variable t3 |
-| CSharp7.cs:90:28:90:29 | access to local variable t1 | CSharp7.cs:90:9:90:24 | (..., ...) |
-| CSharp7.cs:90:28:90:29 | access to local variable t1 | CSharp7.cs:92:20:92:21 | access to local variable t1 |
-| CSharp7.cs:109:9:109:46 | SSA def(m1) | CSharp7.cs:112:27:112:28 | access to local variable m1 |
-| CSharp7.cs:109:9:109:46 | SSA def(m2) | CSharp7.cs:112:31:112:32 | access to local variable m2 |
-| CSharp7.cs:109:28:109:46 | (..., ...) | CSharp7.cs:109:9:109:24 | (..., ...) |
-| CSharp7.cs:109:29:109:37 | "DefUse1" | CSharp7.cs:109:9:109:46 | SSA def(m1) |
-| CSharp7.cs:109:40:109:45 | (..., ...) | CSharp7.cs:109:9:109:46 | SSA def(m2) |
-| CSharp7.cs:112:9:112:33 | SSA def(m4) | CSharp7.cs:113:18:113:19 | access to local variable m4 |
-| CSharp7.cs:112:26:112:33 | (..., ...) | CSharp7.cs:112:9:112:22 | (..., ...) |
-| CSharp7.cs:114:9:114:67 | SSA def(m9) | CSharp7.cs:115:19:115:20 | access to local variable m9 |
-| CSharp7.cs:114:38:114:67 | ... = ... | CSharp7.cs:114:9:114:34 | (..., ...) |
-| CSharp7.cs:114:38:114:67 | SSA def(m2) | CSharp7.cs:118:9:118:10 | access to local variable m2 |
-| CSharp7.cs:114:38:114:67 | SSA qualifier def(m2.Item1) | CSharp7.cs:119:19:119:26 | access to field Item1 |
-| CSharp7.cs:114:49:114:67 | (..., ...) | CSharp7.cs:114:38:114:45 | (..., ...) |
-| CSharp7.cs:114:49:114:67 | (..., ...) | CSharp7.cs:114:38:114:67 | ... = ... |
-| CSharp7.cs:114:61:114:66 | (..., ...) | CSharp7.cs:114:38:114:67 | SSA def(m2) |
-| CSharp7.cs:118:9:118:10 | [post] access to local variable m2 | CSharp7.cs:119:19:119:20 | access to local variable m2 |
-| CSharp7.cs:118:9:118:10 | access to local variable m2 | CSharp7.cs:119:19:119:20 | access to local variable m2 |
-| CSharp7.cs:123:28:123:36 | "DefUse3" | CSharp7.cs:123:22:123:36 | ... = ... |
-| CSharp7.cs:129:9:129:12 | this | CSharp7.cs:135:24:135:25 | this access |
-| CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:32:131:32 | access to parameter x |
-| CSharp7.cs:131:32:131:32 | access to parameter x | CSharp7.cs:131:32:131:36 | ... + ... |
-| CSharp7.cs:131:36:131:36 | 1 | CSharp7.cs:131:32:131:36 | ... + ... |
-| CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:39:133:39 | access to parameter t |
-| CSharp7.cs:135:24:135:25 | this access | CSharp7.cs:156:16:156:17 | this access |
-| CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:34:139:34 | access to parameter x |
-| CSharp7.cs:139:34:139:34 | access to parameter x | CSharp7.cs:139:34:139:38 | ... + ... |
-| CSharp7.cs:139:38:139:38 | 1 | CSharp7.cs:139:34:139:38 | ... + ... |
-| CSharp7.cs:141:9:141:51 | this | CSharp7.cs:141:38:141:39 | this access |
-| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:26:141:26 | access to parameter x |
-| CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:26:141:30 | ... > ... |
-| CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:41:141:41 | access to parameter x |
-| CSharp7.cs:141:34:141:34 | 1 | CSharp7.cs:141:34:141:46 | ... + ... |
-| CSharp7.cs:141:34:141:46 | ... + ... | CSharp7.cs:141:26:141:50 | ... ? ... : ... |
-| CSharp7.cs:141:38:141:46 | call to local function f7 | CSharp7.cs:141:34:141:46 | ... + ... |
-| CSharp7.cs:141:50:141:50 | 0 | CSharp7.cs:141:26:141:50 | ... ? ... : ... |
-| CSharp7.cs:143:9:143:31 | this | CSharp7.cs:143:26:143:27 | this access |
-| CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:29:143:29 | access to parameter x |
-| CSharp7.cs:145:9:149:9 | this | CSharp7.cs:148:20:148:21 | this access |
-| CSharp7.cs:147:13:147:35 | this | CSharp7.cs:147:30:147:31 | this access |
-| CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x |
-| CSharp7.cs:159:10:159:17 | this | CSharp7.cs:171:9:171:9 | this access |
-| CSharp7.cs:162:18:162:18 | t | CSharp7.cs:162:24:162:24 | access to parameter t |
-| CSharp7.cs:164:9:169:9 | this | CSharp7.cs:167:13:167:16 | this access |
-| CSharp7.cs:164:26:164:26 | u | CSharp7.cs:168:22:168:22 | access to parameter u |
-| CSharp7.cs:166:13:166:43 | this | CSharp7.cs:166:37:166:40 | this access |
-| CSharp7.cs:167:13:167:16 | this access | CSharp7.cs:168:20:168:20 | this access |
-| CSharp7.cs:171:9:171:9 | this access | CSharp7.cs:172:9:172:9 | this access |
-| CSharp7.cs:175:10:175:19 | this | CSharp7.cs:182:21:182:21 | this access |
-| CSharp7.cs:177:16:177:30 | SSA def(src) | CSharp7.cs:182:23:182:25 | access to local variable src |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:16:177:30 | SSA def(src) |
-| CSharp7.cs:178:9:178:40 | this | CSharp7.cs:178:31:178:31 | this access |
-| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:33:178:33 | access to parameter s |
-| CSharp7.cs:178:31:178:34 | call to local function g | CSharp7.cs:178:31:178:39 | ... + ... |
-| CSharp7.cs:178:38:178:39 | "" | CSharp7.cs:178:31:178:39 | ... + ... |
-| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:31:179:31 | access to parameter s |
-| CSharp7.cs:180:25:180:25 | s | CSharp7.cs:180:37:180:37 | access to parameter s |
-| CSharp7.cs:182:21:182:21 | this access | CSharp7.cs:183:21:183:21 | this access |
-| CSharp7.cs:182:23:182:25 | [post] access to local variable src | CSharp7.cs:183:23:183:25 | access to local variable src |
-| CSharp7.cs:182:23:182:25 | access to local variable src | CSharp7.cs:183:23:183:25 | access to local variable src |
-| CSharp7.cs:183:21:183:21 | this access | CSharp7.cs:184:21:184:21 | this access |
-| CSharp7.cs:183:23:183:25 | [post] access to local variable src | CSharp7.cs:184:23:184:25 | access to local variable src |
-| CSharp7.cs:183:23:183:25 | access to local variable src | CSharp7.cs:184:23:184:25 | access to local variable src |
-| CSharp7.cs:190:10:190:11 | this | CSharp7.cs:199:14:199:23 | this access |
-| CSharp7.cs:192:13:192:18 | SSA def(v1) | CSharp7.cs:193:26:193:27 | access to local variable v1 |
-| CSharp7.cs:192:18:192:18 | 2 | CSharp7.cs:192:13:192:18 | SSA def(v1) |
-| CSharp7.cs:193:22:193:27 | ref ... | CSharp7.cs:193:17:193:27 | SSA def(r1) |
-| CSharp7.cs:193:26:193:27 | access to local variable v1 | CSharp7.cs:199:21:199:22 | access to local variable v1 |
-| CSharp7.cs:194:13:194:31 | SSA def(array) | CSharp7.cs:196:14:196:18 | access to local variable array |
-| CSharp7.cs:194:21:194:31 | array creation of type Int32[] | CSharp7.cs:194:13:194:31 | SSA def(array) |
-| CSharp7.cs:195:14:195:14 | 3 | CSharp7.cs:195:9:195:14 | SSA def(r1) |
-| CSharp7.cs:196:9:196:21 | SSA def(r1) | CSharp7.cs:198:26:198:27 | access to local variable r1 |
-| CSharp7.cs:196:14:196:18 | access to local variable array | CSharp7.cs:196:14:196:21 | access to array element |
-| CSharp7.cs:196:14:196:18 | access to local variable array | CSharp7.cs:197:26:197:30 | access to local variable array |
-| CSharp7.cs:196:14:196:21 | access to array element | CSharp7.cs:196:9:196:21 | SSA def(r1) |
-| CSharp7.cs:197:26:197:30 | access to local variable array | CSharp7.cs:197:26:197:33 | access to array element |
-| CSharp7.cs:198:26:198:27 | access to local variable r1 | CSharp7.cs:200:33:200:34 | access to local variable r1 |
-| CSharp7.cs:199:14:199:23 | [post] this access | CSharp7.cs:200:26:200:35 | this access |
-| CSharp7.cs:199:14:199:23 | this access | CSharp7.cs:200:26:200:35 | this access |
-| CSharp7.cs:200:26:200:35 | [post] this access | CSharp7.cs:201:9:201:18 | this access |
-| CSharp7.cs:200:26:200:35 | this access | CSharp7.cs:201:9:201:18 | this access |
-| CSharp7.cs:200:33:200:34 | access to local variable r1 | CSharp7.cs:201:16:201:17 | access to local variable r1 |
-| CSharp7.cs:204:24:204:24 | p | CSharp7.cs:207:20:207:20 | access to parameter p |
-| CSharp7.cs:206:28:206:28 | q | CSharp7.cs:206:44:206:44 | access to parameter q |
-| CSharp7.cs:217:13:217:17 | false | CSharp7.cs:217:9:217:17 | SSA def(x) |
-| CSharp7.cs:221:10:221:13 | this | CSharp7.cs:223:13:223:20 | this access |
-| CSharp7.cs:223:13:223:20 | [post] this access | CSharp7.cs:224:18:224:25 | this access |
-| CSharp7.cs:223:13:223:20 | this access | CSharp7.cs:224:18:224:25 | this access |
-| CSharp7.cs:224:18:224:25 | [post] this access | CSharp7.cs:225:22:225:29 | this access |
-| CSharp7.cs:224:18:224:25 | call to method f | CSharp7.cs:224:9:224:14 | (..., ...) |
-| CSharp7.cs:224:18:224:25 | this access | CSharp7.cs:225:22:225:29 | this access |
-| CSharp7.cs:225:22:225:29 | [post] this access | CSharp7.cs:226:22:226:33 | this access |
-| CSharp7.cs:225:22:225:29 | call to method f | CSharp7.cs:225:9:225:18 | (..., ...) |
-| CSharp7.cs:225:22:225:29 | this access | CSharp7.cs:226:22:226:33 | this access |
-| CSharp7.cs:226:22:226:33 | call to method f | CSharp7.cs:226:9:226:18 | (..., ...) |
-| CSharp7.cs:234:16:234:23 | SSA def(o) | CSharp7.cs:235:13:235:13 | access to local variable o |
-| CSharp7.cs:234:20:234:23 | null | CSharp7.cs:234:16:234:23 | SSA def(o) |
-| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:235:18:235:23 | SSA def(i1) |
-| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:239:18:239:18 | access to local variable o |
-| CSharp7.cs:235:13:235:13 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o |
-| CSharp7.cs:235:13:235:23 | [false] ... is ... | CSharp7.cs:235:13:235:33 | [false] ... && ... |
-| CSharp7.cs:235:13:235:23 | [true] ... is ... | CSharp7.cs:235:13:235:33 | [false] ... && ... |
-| CSharp7.cs:235:13:235:23 | [true] ... is ... | CSharp7.cs:235:13:235:33 | [true] ... && ... |
-| CSharp7.cs:235:18:235:23 | SSA def(i1) | CSharp7.cs:235:28:235:29 | access to local variable i1 |
-| CSharp7.cs:235:28:235:29 | access to local variable i1 | CSharp7.cs:235:28:235:33 | ... > ... |
-| CSharp7.cs:235:28:235:29 | access to local variable i1 | CSharp7.cs:237:38:237:39 | access to local variable i1 |
-| CSharp7.cs:235:28:235:33 | ... > ... | CSharp7.cs:235:13:235:33 | [false] ... && ... |
-| CSharp7.cs:235:28:235:33 | ... > ... | CSharp7.cs:235:13:235:33 | [true] ... && ... |
-| CSharp7.cs:237:33:237:36 | "int " | CSharp7.cs:237:31:237:41 | $"..." |
-| CSharp7.cs:237:38:237:39 | access to local variable i1 | CSharp7.cs:237:31:237:41 | $"..." |
-| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:239:23:239:31 | SSA def(s1) |
-| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:243:18:243:18 | access to local variable o |
-| CSharp7.cs:239:18:239:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o |
-| CSharp7.cs:239:23:239:31 | SSA def(s1) | CSharp7.cs:241:41:241:42 | access to local variable s1 |
-| CSharp7.cs:241:33:241:39 | "string " | CSharp7.cs:241:31:241:44 | $"..." |
-| CSharp7.cs:241:41:241:42 | access to local variable s1 | CSharp7.cs:241:31:241:44 | $"..." |
-| CSharp7.cs:243:18:243:18 | access to local variable o | CSharp7.cs:246:18:246:18 | access to local variable o |
-| CSharp7.cs:243:18:243:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o |
-| CSharp7.cs:246:18:246:18 | access to local variable o | CSharp7.cs:250:17:250:17 | access to local variable o |
-| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:256:27:256:27 | access to local variable o |
-| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:259:18:259:23 | SSA def(i2) |
-| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:262:18:262:23 | SSA def(i3) |
-| CSharp7.cs:250:17:250:17 | access to local variable o | CSharp7.cs:265:18:265:26 | SSA def(s2) |
-| CSharp7.cs:254:26:254:26 | 1 | CSharp7.cs:254:26:254:30 | ... < ... |
-| CSharp7.cs:254:30:254:30 | 2 | CSharp7.cs:254:26:254:30 | ... < ... |
-| CSharp7.cs:256:27:256:27 | access to local variable o | CSharp7.cs:256:32:256:40 | SSA def(s4) |
-| CSharp7.cs:256:32:256:40 | SSA def(s4) | CSharp7.cs:257:40:257:41 | access to local variable s4 |
-| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:35:257:43 | $"..." |
-| CSharp7.cs:257:40:257:41 | access to local variable s4 | CSharp7.cs:257:35:257:43 | $"..." |
-| CSharp7.cs:259:18:259:23 | SSA def(i2) | CSharp7.cs:259:30:259:31 | access to local variable i2 |
-| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:259:30:259:35 | ... > ... |
-| CSharp7.cs:259:30:259:31 | access to local variable i2 | CSharp7.cs:260:47:260:48 | access to local variable i2 |
-| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:35:260:50 | $"..." |
-| CSharp7.cs:260:47:260:48 | access to local variable i2 | CSharp7.cs:260:35:260:50 | $"..." |
-| CSharp7.cs:262:18:262:23 | SSA def(i3) | CSharp7.cs:263:42:263:43 | access to local variable i3 |
-| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:35:263:45 | $"..." |
-| CSharp7.cs:263:42:263:43 | access to local variable i3 | CSharp7.cs:263:35:263:45 | $"..." |
-| CSharp7.cs:265:18:265:26 | SSA def(s2) | CSharp7.cs:266:45:266:46 | access to local variable s2 |
-| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:35:266:48 | $"..." |
-| CSharp7.cs:266:45:266:46 | access to local variable s2 | CSharp7.cs:266:35:266:48 | $"..." |
-| CSharp7.cs:284:13:284:48 | SSA def(dict) | CSharp7.cs:285:20:285:23 | access to local variable dict |
-| CSharp7.cs:284:20:284:48 | object creation of type Dictionary | CSharp7.cs:284:13:284:48 | SSA def(dict) |
-| CSharp7.cs:285:13:285:62 | SSA def(list) | CSharp7.cs:287:39:287:42 | access to local variable list |
-| CSharp7.cs:285:20:285:62 | call to method Select | CSharp7.cs:285:13:285:62 | SSA def(list) |
-| CSharp7.cs:285:32:285:35 | item | CSharp7.cs:285:41:285:44 | access to parameter item |
-| CSharp7.cs:285:41:285:44 | access to parameter item | CSharp7.cs:285:51:285:54 | access to parameter item |
-| CSharp7.cs:287:39:287:42 | access to local variable list | CSharp7.cs:289:36:289:39 | access to local variable list |
-| CSharp7.cs:289:36:289:39 | access to local variable list | CSharp7.cs:291:32:291:35 | access to local variable list |
-| CSharp7.cs:299:18:299:22 | SSA def(x) | CSharp7.cs:299:25:299:25 | SSA phi(x) |
-| CSharp7.cs:299:22:299:22 | 0 | CSharp7.cs:299:18:299:22 | SSA def(x) |
-| CSharp7.cs:299:25:299:25 | SSA phi(x) | CSharp7.cs:299:25:299:25 | access to local variable x |
-| CSharp7.cs:299:25:299:25 | access to local variable x | CSharp7.cs:299:25:299:30 | ... < ... |
-| CSharp7.cs:299:25:299:25 | access to local variable x | CSharp7.cs:299:35:299:35 | access to local variable x |
-| CSharp7.cs:299:25:299:30 | ... < ... | CSharp7.cs:299:25:299:44 | [false] ... && ... |
-| CSharp7.cs:299:25:299:30 | ... < ... | CSharp7.cs:299:25:299:44 | [true] ... && ... |
-| CSharp7.cs:299:35:299:35 | access to local variable x | CSharp7.cs:299:40:299:44 | SSA def(y) |
-| CSharp7.cs:299:35:299:35 | access to local variable x | CSharp7.cs:299:49:299:49 | access to local variable x |
-| CSharp7.cs:299:35:299:44 | [false] ... is ... | CSharp7.cs:299:25:299:44 | [false] ... && ... |
-| CSharp7.cs:299:35:299:44 | [true] ... is ... | CSharp7.cs:299:25:299:44 | [true] ... && ... |
-| CSharp7.cs:299:40:299:44 | SSA def(y) | CSharp7.cs:301:31:301:31 | access to local variable y |
-| CSharp7.cs:299:47:299:49 | SSA def(x) | CSharp7.cs:299:25:299:25 | SSA phi(x) |
+| CSharp7.cs:5:7:5:14 | this | CSharp7.cs:7:9:7:9 | this access |
+| CSharp7.cs:7:9:7:9 | [post] this access | CSharp7.cs:8:9:8:9 | this access |
+| CSharp7.cs:7:9:7:9 | this access | CSharp7.cs:8:9:8:9 | this access |
+| CSharp7.cs:8:9:8:9 | [post] this access | CSharp7.cs:9:9:9:9 | this access |
+| CSharp7.cs:8:9:8:9 | this access | CSharp7.cs:9:9:9:9 | this access |
+| CSharp7.cs:14:9:14:13 | [post] this access | CSharp7.cs:23:39:23:43 | this access |
+| CSharp7.cs:14:9:14:13 | this access | CSharp7.cs:23:39:23:43 | this access |
+| CSharp7.cs:15:9:15:11 | SSA entry def(this.field) | CSharp7.cs:15:18:15:22 | access to field field |
+| CSharp7.cs:15:9:15:11 | this | CSharp7.cs:15:18:15:22 | this access |
+| CSharp7.cs:19:9:19:11 | this | CSharp7.cs:19:16:19:20 | this access |
+| CSharp7.cs:20:9:20:11 | this | CSharp7.cs:20:16:20:20 | this access |
+| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:24:20:28 | access to parameter value |
+| CSharp7.cs:23:5:23:27 | this | CSharp7.cs:14:9:14:13 | this access |
+| CSharp7.cs:24:6:24:28 | this | CSharp7.cs:24:35:24:39 | this access |
+| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:31:16:31:16 | access to parameter i |
+| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... |
+| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i |
+| CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... |
+| CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:21 | SSA def(x) |
+| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:44:13:44:13 | access to parameter x |
+| CSharp7.cs:44:13:44:13 | access to parameter x | CSharp7.cs:44:9:44:13 | SSA def(y) |
+| CSharp7.cs:47:10:47:10 | this | CSharp7.cs:49:9:49:24 | this access |
+| CSharp7.cs:49:9:49:24 | [post] this access | CSharp7.cs:50:9:50:21 | this access |
+| CSharp7.cs:49:9:49:24 | this access | CSharp7.cs:50:9:50:21 | this access |
+| CSharp7.cs:49:22:49:23 | SSA def(t1) | CSharp7.cs:51:18:51:19 | access to local variable t1 |
+| CSharp7.cs:50:9:50:21 | [post] this access | CSharp7.cs:52:9:52:17 | this access |
+| CSharp7.cs:50:9:50:21 | this access | CSharp7.cs:52:9:52:17 | this access |
+| CSharp7.cs:50:19:50:20 | SSA def(t2) | CSharp7.cs:54:14:54:15 | access to local variable t2 |
+| CSharp7.cs:52:9:52:17 | [post] this access | CSharp7.cs:55:9:55:32 | this access |
+| CSharp7.cs:52:9:52:17 | this access | CSharp7.cs:55:9:55:32 | this access |
+| CSharp7.cs:52:15:52:16 | SSA def(t1) | CSharp7.cs:53:14:53:15 | access to local variable t1 |
+| CSharp7.cs:55:30:55:31 | SSA def(t4) | CSharp7.cs:56:18:56:19 | access to local variable t4 |
+| CSharp7.cs:67:10:67:20 | this | CSharp7.cs:69:26:69:28 | this access |
+| CSharp7.cs:69:26:69:28 | [post] this access | CSharp7.cs:70:17:70:19 | this access |
+| CSharp7.cs:69:26:69:28 | call to method F | CSharp7.cs:69:9:69:22 | (..., ...) |
+| CSharp7.cs:69:26:69:28 | this access | CSharp7.cs:70:17:70:19 | this access |
+| CSharp7.cs:70:13:70:19 | SSA def(z) | CSharp7.cs:73:16:73:16 | access to local variable z |
+| CSharp7.cs:70:17:70:19 | [post] this access | CSharp7.cs:71:18:71:20 | this access |
+| CSharp7.cs:70:17:70:19 | call to method F | CSharp7.cs:70:13:70:19 | SSA def(z) |
+| CSharp7.cs:70:17:70:19 | this access | CSharp7.cs:71:18:71:20 | this access |
+| CSharp7.cs:71:18:71:20 | [post] this access | CSharp7.cs:72:13:72:15 | this access |
+| CSharp7.cs:71:18:71:20 | call to method F | CSharp7.cs:71:9:71:14 | (..., ...) |
+| CSharp7.cs:71:18:71:20 | this access | CSharp7.cs:72:13:72:15 | this access |
+| CSharp7.cs:73:16:73:16 | [post] access to local variable z | CSharp7.cs:75:39:75:39 | access to local variable z |
+| CSharp7.cs:73:16:73:16 | access to local variable z | CSharp7.cs:75:39:75:39 | access to local variable z |
+| CSharp7.cs:73:27:73:35 | (..., ...) | CSharp7.cs:73:9:73:23 | (..., ...) |
+| CSharp7.cs:74:9:74:32 | SSA def(x) | CSharp7.cs:77:27:77:27 | access to local variable x |
+| CSharp7.cs:74:18:74:32 | ... = ... | CSharp7.cs:74:9:74:14 | (..., ...) |
+| CSharp7.cs:74:27:74:32 | (..., ...) | CSharp7.cs:74:18:74:23 | (..., ...) |
+| CSharp7.cs:74:27:74:32 | (..., ...) | CSharp7.cs:74:18:74:32 | ... = ... |
+| CSharp7.cs:75:9:75:40 | SSA def(a) | CSharp7.cs:76:31:76:31 | access to local variable a |
+| CSharp7.cs:75:9:75:40 | SSA def(b) | CSharp7.cs:76:24:76:24 | access to local variable b |
+| CSharp7.cs:75:9:75:40 | SSA def(c) | CSharp7.cs:76:28:76:28 | access to local variable c |
+| CSharp7.cs:75:35:75:40 | (..., ...) | CSharp7.cs:75:9:75:31 | (..., ...) |
+| CSharp7.cs:75:36:75:36 | 1 | CSharp7.cs:75:9:75:40 | SSA def(a) |
+| CSharp7.cs:76:23:76:33 | (..., ...) | CSharp7.cs:76:9:76:19 | (..., ...) |
+| CSharp7.cs:77:22:77:28 | (..., ...) | CSharp7.cs:77:9:77:18 | (..., ...) |
+| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:82:20:82:20 | access to parameter x |
+| CSharp7.cs:85:10:85:18 | this | CSharp7.cs:90:18:90:28 | this access |
+| CSharp7.cs:87:13:87:34 | SSA def(t1) | CSharp7.cs:88:28:88:29 | access to local variable t1 |
+| CSharp7.cs:87:13:87:34 | SSA qualifier def(t1.Item1) | CSharp7.cs:90:20:90:27 | access to field Item1 |
+| CSharp7.cs:87:18:87:34 | (..., ...) | CSharp7.cs:87:13:87:34 | SSA def(t1) |
+| CSharp7.cs:88:9:88:29 | SSA def(t3) | CSharp7.cs:89:18:89:19 | access to local variable t3 |
+| CSharp7.cs:88:28:88:29 | access to local variable t1 | CSharp7.cs:88:9:88:24 | (..., ...) |
+| CSharp7.cs:88:28:88:29 | access to local variable t1 | CSharp7.cs:90:20:90:21 | access to local variable t1 |
+| CSharp7.cs:107:9:107:46 | SSA def(m1) | CSharp7.cs:110:27:110:28 | access to local variable m1 |
+| CSharp7.cs:107:9:107:46 | SSA def(m2) | CSharp7.cs:110:31:110:32 | access to local variable m2 |
+| CSharp7.cs:107:28:107:46 | (..., ...) | CSharp7.cs:107:9:107:24 | (..., ...) |
+| CSharp7.cs:107:29:107:37 | "DefUse1" | CSharp7.cs:107:9:107:46 | SSA def(m1) |
+| CSharp7.cs:107:40:107:45 | (..., ...) | CSharp7.cs:107:9:107:46 | SSA def(m2) |
+| CSharp7.cs:110:9:110:33 | SSA def(m4) | CSharp7.cs:111:18:111:19 | access to local variable m4 |
+| CSharp7.cs:110:26:110:33 | (..., ...) | CSharp7.cs:110:9:110:22 | (..., ...) |
+| CSharp7.cs:112:9:112:67 | SSA def(m9) | CSharp7.cs:113:19:113:20 | access to local variable m9 |
+| CSharp7.cs:112:38:112:67 | ... = ... | CSharp7.cs:112:9:112:34 | (..., ...) |
+| CSharp7.cs:112:38:112:67 | SSA def(m2) | CSharp7.cs:116:9:116:10 | access to local variable m2 |
+| CSharp7.cs:112:38:112:67 | SSA qualifier def(m2.Item1) | CSharp7.cs:117:19:117:26 | access to field Item1 |
+| CSharp7.cs:112:49:112:67 | (..., ...) | CSharp7.cs:112:38:112:45 | (..., ...) |
+| CSharp7.cs:112:49:112:67 | (..., ...) | CSharp7.cs:112:38:112:67 | ... = ... |
+| CSharp7.cs:112:61:112:66 | (..., ...) | CSharp7.cs:112:38:112:67 | SSA def(m2) |
+| CSharp7.cs:116:9:116:10 | [post] access to local variable m2 | CSharp7.cs:117:19:117:20 | access to local variable m2 |
+| CSharp7.cs:116:9:116:10 | access to local variable m2 | CSharp7.cs:117:19:117:20 | access to local variable m2 |
+| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:36 | ... = ... |
+| CSharp7.cs:127:9:127:12 | this | CSharp7.cs:133:24:133:25 | this access |
+| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:32:129:32 | access to parameter x |
+| CSharp7.cs:129:32:129:32 | access to parameter x | CSharp7.cs:129:32:129:36 | ... + ... |
+| CSharp7.cs:129:36:129:36 | 1 | CSharp7.cs:129:32:129:36 | ... + ... |
+| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:39:131:39 | access to parameter t |
+| CSharp7.cs:133:24:133:25 | this access | CSharp7.cs:154:16:154:17 | this access |
+| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:34:137:34 | access to parameter x |
+| CSharp7.cs:137:34:137:34 | access to parameter x | CSharp7.cs:137:34:137:38 | ... + ... |
+| CSharp7.cs:137:38:137:38 | 1 | CSharp7.cs:137:34:137:38 | ... + ... |
+| CSharp7.cs:139:9:139:51 | this | CSharp7.cs:139:38:139:39 | this access |
+| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:26:139:26 | access to parameter x |
+| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:26:139:30 | ... > ... |
+| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:41:139:41 | access to parameter x |
+| CSharp7.cs:139:34:139:34 | 1 | CSharp7.cs:139:34:139:46 | ... + ... |
+| CSharp7.cs:139:34:139:46 | ... + ... | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
+| CSharp7.cs:139:38:139:46 | call to local function f7 | CSharp7.cs:139:34:139:46 | ... + ... |
+| CSharp7.cs:139:50:139:50 | 0 | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
+| CSharp7.cs:141:9:141:31 | this | CSharp7.cs:141:26:141:27 | this access |
+| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:29:141:29 | access to parameter x |
+| CSharp7.cs:143:9:147:9 | this | CSharp7.cs:146:20:146:21 | this access |
+| CSharp7.cs:145:13:145:35 | this | CSharp7.cs:145:30:145:31 | this access |
+| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:33:145:33 | access to parameter x |
+| CSharp7.cs:157:10:157:17 | this | CSharp7.cs:169:9:169:9 | this access |
+| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:24:160:24 | access to parameter t |
+| CSharp7.cs:162:9:167:9 | this | CSharp7.cs:165:13:165:16 | this access |
+| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:166:22:166:22 | access to parameter u |
+| CSharp7.cs:164:13:164:43 | this | CSharp7.cs:164:37:164:40 | this access |
+| CSharp7.cs:165:13:165:16 | this access | CSharp7.cs:166:20:166:20 | this access |
+| CSharp7.cs:169:9:169:9 | this access | CSharp7.cs:170:9:170:9 | this access |
+| CSharp7.cs:173:10:173:19 | this | CSharp7.cs:180:21:180:21 | this access |
+| CSharp7.cs:175:16:175:30 | SSA def(src) | CSharp7.cs:180:23:180:25 | access to local variable src |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:16:175:30 | SSA def(src) |
+| CSharp7.cs:176:9:176:40 | this | CSharp7.cs:176:31:176:31 | this access |
+| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:33:176:33 | access to parameter s |
+| CSharp7.cs:176:31:176:34 | call to local function g | CSharp7.cs:176:31:176:39 | ... + ... |
+| CSharp7.cs:176:38:176:39 | "" | CSharp7.cs:176:31:176:39 | ... + ... |
+| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:31:177:31 | access to parameter s |
+| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:37:178:37 | access to parameter s |
+| CSharp7.cs:180:21:180:21 | this access | CSharp7.cs:181:21:181:21 | this access |
+| CSharp7.cs:180:23:180:25 | [post] access to local variable src | CSharp7.cs:181:23:181:25 | access to local variable src |
+| CSharp7.cs:180:23:180:25 | access to local variable src | CSharp7.cs:181:23:181:25 | access to local variable src |
+| CSharp7.cs:181:21:181:21 | this access | CSharp7.cs:182:21:182:21 | this access |
+| CSharp7.cs:181:23:181:25 | [post] access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src |
+| CSharp7.cs:181:23:181:25 | access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src |
+| CSharp7.cs:188:10:188:11 | this | CSharp7.cs:197:14:197:23 | this access |
+| CSharp7.cs:190:13:190:18 | SSA def(v1) | CSharp7.cs:191:26:191:27 | access to local variable v1 |
+| CSharp7.cs:190:18:190:18 | 2 | CSharp7.cs:190:13:190:18 | SSA def(v1) |
+| CSharp7.cs:191:22:191:27 | ref ... | CSharp7.cs:191:17:191:27 | SSA def(r1) |
+| CSharp7.cs:191:26:191:27 | access to local variable v1 | CSharp7.cs:197:21:197:22 | access to local variable v1 |
+| CSharp7.cs:192:13:192:31 | SSA def(array) | CSharp7.cs:194:14:194:18 | access to local variable array |
+| CSharp7.cs:192:21:192:31 | array creation of type Int32[] | CSharp7.cs:192:13:192:31 | SSA def(array) |
+| CSharp7.cs:193:14:193:14 | 3 | CSharp7.cs:193:9:193:14 | SSA def(r1) |
+| CSharp7.cs:194:9:194:21 | SSA def(r1) | CSharp7.cs:196:26:196:27 | access to local variable r1 |
+| CSharp7.cs:194:14:194:18 | access to local variable array | CSharp7.cs:194:14:194:21 | access to array element |
+| CSharp7.cs:194:14:194:18 | access to local variable array | CSharp7.cs:195:26:195:30 | access to local variable array |
+| CSharp7.cs:194:14:194:21 | access to array element | CSharp7.cs:194:9:194:21 | SSA def(r1) |
+| CSharp7.cs:195:26:195:30 | access to local variable array | CSharp7.cs:195:26:195:33 | access to array element |
+| CSharp7.cs:196:26:196:27 | access to local variable r1 | CSharp7.cs:198:33:198:34 | access to local variable r1 |
+| CSharp7.cs:197:14:197:23 | [post] this access | CSharp7.cs:198:26:198:35 | this access |
+| CSharp7.cs:197:14:197:23 | this access | CSharp7.cs:198:26:198:35 | this access |
+| CSharp7.cs:198:26:198:35 | [post] this access | CSharp7.cs:199:9:199:18 | this access |
+| CSharp7.cs:198:26:198:35 | this access | CSharp7.cs:199:9:199:18 | this access |
+| CSharp7.cs:198:33:198:34 | access to local variable r1 | CSharp7.cs:199:16:199:17 | access to local variable r1 |
+| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:205:20:205:20 | access to parameter p |
+| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:44:204:44 | access to parameter q |
+| CSharp7.cs:215:13:215:17 | false | CSharp7.cs:215:9:215:17 | SSA def(x) |
+| CSharp7.cs:219:10:219:13 | this | CSharp7.cs:221:13:221:20 | this access |
+| CSharp7.cs:221:13:221:20 | [post] this access | CSharp7.cs:222:18:222:25 | this access |
+| CSharp7.cs:221:13:221:20 | this access | CSharp7.cs:222:18:222:25 | this access |
+| CSharp7.cs:222:18:222:25 | [post] this access | CSharp7.cs:223:22:223:29 | this access |
+| CSharp7.cs:222:18:222:25 | call to method f | CSharp7.cs:222:9:222:14 | (..., ...) |
+| CSharp7.cs:222:18:222:25 | this access | CSharp7.cs:223:22:223:29 | this access |
+| CSharp7.cs:223:22:223:29 | [post] this access | CSharp7.cs:224:22:224:33 | this access |
+| CSharp7.cs:223:22:223:29 | call to method f | CSharp7.cs:223:9:223:18 | (..., ...) |
+| CSharp7.cs:223:22:223:29 | this access | CSharp7.cs:224:22:224:33 | this access |
+| CSharp7.cs:224:22:224:33 | call to method f | CSharp7.cs:224:9:224:18 | (..., ...) |
+| CSharp7.cs:232:16:232:23 | SSA def(o) | CSharp7.cs:233:13:233:13 | access to local variable o |
+| CSharp7.cs:232:20:232:23 | null | CSharp7.cs:232:16:232:23 | SSA def(o) |
+| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | SSA def(i1) |
+| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o |
+| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:248:17:248:17 | access to local variable o |
+| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
+| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
+| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
+| CSharp7.cs:233:18:233:23 | SSA def(i1) | CSharp7.cs:233:28:233:29 | access to local variable i1 |
+| CSharp7.cs:233:28:233:29 | access to local variable i1 | CSharp7.cs:233:28:233:33 | ... > ... |
+| CSharp7.cs:233:28:233:29 | access to local variable i1 | CSharp7.cs:235:38:235:39 | access to local variable i1 |
+| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
+| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
+| CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." |
+| CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." |
+| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | SSA def(s1) |
+| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o |
+| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:248:17:248:17 | access to local variable o |
+| CSharp7.cs:237:23:237:31 | SSA def(s1) | CSharp7.cs:239:41:239:42 | access to local variable s1 |
+| CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." |
+| CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." |
+| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o |
+| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:248:17:248:17 | access to local variable o |
+| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:248:17:248:17 | access to local variable o |
+| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:27:254:27 | access to local variable o |
+| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | SSA def(i2) |
+| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:260:18:260:23 | SSA def(i3) |
+| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:263:18:263:26 | SSA def(s2) |
+| CSharp7.cs:252:26:252:26 | 1 | CSharp7.cs:252:26:252:30 | ... < ... |
+| CSharp7.cs:252:30:252:30 | 2 | CSharp7.cs:252:26:252:30 | ... < ... |
+| CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | SSA def(s4) |
+| CSharp7.cs:254:32:254:40 | SSA def(s4) | CSharp7.cs:255:40:255:41 | access to local variable s4 |
+| CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:35:255:43 | $"..." |
+| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:35:255:43 | $"..." |
+| CSharp7.cs:257:18:257:23 | SSA def(i2) | CSharp7.cs:257:30:257:31 | access to local variable i2 |
+| CSharp7.cs:257:30:257:31 | access to local variable i2 | CSharp7.cs:257:30:257:35 | ... > ... |
+| CSharp7.cs:257:30:257:31 | access to local variable i2 | CSharp7.cs:258:47:258:48 | access to local variable i2 |
+| CSharp7.cs:258:37:258:45 | "positive " | CSharp7.cs:258:35:258:50 | $"..." |
+| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:35:258:50 | $"..." |
+| CSharp7.cs:260:18:260:23 | SSA def(i3) | CSharp7.cs:261:42:261:43 | access to local variable i3 |
+| CSharp7.cs:261:37:261:40 | "int " | CSharp7.cs:261:35:261:45 | $"..." |
+| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:35:261:45 | $"..." |
+| CSharp7.cs:263:18:263:26 | SSA def(s2) | CSharp7.cs:264:45:264:46 | access to local variable s2 |
+| CSharp7.cs:264:37:264:43 | "string " | CSharp7.cs:264:35:264:48 | $"..." |
+| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:35:264:48 | $"..." |
+| CSharp7.cs:282:13:282:48 | SSA def(dict) | CSharp7.cs:283:20:283:23 | access to local variable dict |
+| CSharp7.cs:282:20:282:48 | object creation of type Dictionary | CSharp7.cs:282:13:282:48 | SSA def(dict) |
+| CSharp7.cs:283:13:283:62 | SSA def(list) | CSharp7.cs:285:39:285:42 | access to local variable list |
+| CSharp7.cs:283:20:283:62 | call to method Select | CSharp7.cs:283:13:283:62 | SSA def(list) |
+| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:41:283:44 | access to parameter item |
+| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item |
+| CSharp7.cs:285:39:285:42 | access to local variable list | CSharp7.cs:287:36:287:39 | access to local variable list |
+| CSharp7.cs:287:36:287:39 | access to local variable list | CSharp7.cs:289:32:289:35 | access to local variable list |
+| CSharp7.cs:297:18:297:22 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
+| CSharp7.cs:297:22:297:22 | 0 | CSharp7.cs:297:18:297:22 | SSA def(x) |
+| CSharp7.cs:297:25:297:25 | SSA phi(x) | CSharp7.cs:297:25:297:25 | access to local variable x |
+| CSharp7.cs:297:25:297:25 | access to local variable x | CSharp7.cs:297:25:297:30 | ... < ... |
+| CSharp7.cs:297:25:297:25 | access to local variable x | CSharp7.cs:297:35:297:35 | access to local variable x |
+| CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [false] ... && ... |
+| CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
+| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | SSA def(y) |
+| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x |
+| CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... |
+| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
+| CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y |
+| CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
diff --git a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected
index 7e0793d3b43..19ec4516564 100644
--- a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected
+++ b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected
@@ -1,70 +1,70 @@
-| CSharp7.cs:51:22:51:23 | t1 | string |
-| CSharp7.cs:52:19:52:20 | t2 | string |
-| CSharp7.cs:53:13:53:14 | t3 | string |
-| CSharp7.cs:57:30:57:31 | t4 | string |
-| CSharp7.cs:58:13:58:14 | t5 | string |
-| CSharp7.cs:71:14:71:14 | x | int |
-| CSharp7.cs:71:21:71:21 | y | int |
-| CSharp7.cs:72:13:72:13 | z | (int, int) |
-| CSharp7.cs:77:14:77:14 | a | int |
-| CSharp7.cs:77:22:77:22 | b | int |
-| CSharp7.cs:77:29:77:29 | c | int |
-| CSharp7.cs:79:14:79:14 | i | string |
-| CSharp7.cs:79:17:79:17 | j | int |
-| CSharp7.cs:89:13:89:14 | t1 | (string, string) |
-| CSharp7.cs:90:14:90:15 | t2 | string |
-| CSharp7.cs:90:22:90:23 | t3 | string |
-| CSharp7.cs:91:13:91:14 | t4 | string |
-| CSharp7.cs:92:13:92:14 | t5 | string |
-| CSharp7.cs:97:13:97:14 | m1 | (int, string) |
-| CSharp7.cs:98:13:98:14 | m2 | (int, (string, int)) |
-| CSharp7.cs:103:13:103:14 | m1 | string |
-| CSharp7.cs:104:13:104:14 | m2 | (string, int) |
-| CSharp7.cs:109:14:109:15 | m1 | string |
-| CSharp7.cs:109:22:109:23 | m2 | (int, int) |
-| CSharp7.cs:110:16:110:17 | m3 | string |
-| CSharp7.cs:111:13:111:14 | m4 | int |
-| CSharp7.cs:111:17:111:18 | m5 | int |
-| CSharp7.cs:113:13:113:14 | m6 | int |
-| CSharp7.cs:114:14:114:15 | m7 | string |
-| CSharp7.cs:114:23:114:24 | m8 | int |
-| CSharp7.cs:114:31:114:32 | m9 | int |
-| CSharp7.cs:115:13:115:15 | m10 | int |
-| CSharp7.cs:119:13:119:15 | m11 | int |
-| CSharp7.cs:122:16:122:18 | m12 | string |
-| CSharp7.cs:123:16:123:18 | m13 | string |
-| CSharp7.cs:135:19:135:20 | f4 | Func |
-| CSharp7.cs:139:24:139:25 | f5 | Func |
-| CSharp7.cs:151:16:151:16 | a | Action |
-| CSharp7.cs:177:16:177:18 | src | string |
-| CSharp7.cs:182:13:182:17 | sink1 | string |
-| CSharp7.cs:183:13:183:17 | sink2 | string |
-| CSharp7.cs:184:13:184:17 | sink3 | string |
-| CSharp7.cs:192:13:192:14 | v1 | int |
-| CSharp7.cs:193:17:193:18 | r1 | int |
-| CSharp7.cs:194:13:194:17 | array | Int32[] |
-| CSharp7.cs:197:17:197:18 | r2 | int |
-| CSharp7.cs:198:17:198:18 | r3 | int |
-| CSharp7.cs:200:17:200:18 | r4 | int |
-| CSharp7.cs:225:14:225:14 | x | int |
-| CSharp7.cs:226:17:226:17 | y | double |
-| CSharp7.cs:226:32:226:32 | z | bool |
-| CSharp7.cs:234:16:234:16 | o | object |
-| CSharp7.cs:235:22:235:23 | i1 | int |
-| CSharp7.cs:239:30:239:31 | s1 | string |
-| CSharp7.cs:246:27:246:28 | v1 | object |
-| CSharp7.cs:256:39:256:40 | s4 | string |
-| CSharp7.cs:259:22:259:23 | i2 | int |
-| CSharp7.cs:262:22:262:23 | i3 | int |
-| CSharp7.cs:265:25:265:26 | s2 | string |
-| CSharp7.cs:271:22:271:23 | v2 | object |
-| CSharp7.cs:284:13:284:16 | dict | Dictionary |
-| CSharp7.cs:285:13:285:16 | list | IEnumerable<(Int32,String)> |
+| CSharp7.cs:49:22:49:23 | t1 | string |
+| CSharp7.cs:50:19:50:20 | t2 | string |
+| CSharp7.cs:51:13:51:14 | t3 | string |
+| CSharp7.cs:55:30:55:31 | t4 | string |
+| CSharp7.cs:56:13:56:14 | t5 | string |
+| CSharp7.cs:69:14:69:14 | x | int |
+| CSharp7.cs:69:21:69:21 | y | int |
+| CSharp7.cs:70:13:70:13 | z | (int, int) |
+| CSharp7.cs:75:14:75:14 | a | int |
+| CSharp7.cs:75:22:75:22 | b | int |
+| CSharp7.cs:75:29:75:29 | c | int |
+| CSharp7.cs:77:14:77:14 | i | string |
+| CSharp7.cs:77:17:77:17 | j | int |
+| CSharp7.cs:87:13:87:14 | t1 | (string, string) |
+| CSharp7.cs:88:14:88:15 | t2 | string |
+| CSharp7.cs:88:22:88:23 | t3 | string |
+| CSharp7.cs:89:13:89:14 | t4 | string |
+| CSharp7.cs:90:13:90:14 | t5 | string |
+| CSharp7.cs:95:13:95:14 | m1 | (int, string) |
+| CSharp7.cs:96:13:96:14 | m2 | (int, (string, int)) |
+| CSharp7.cs:101:13:101:14 | m1 | string |
+| CSharp7.cs:102:13:102:14 | m2 | (string, int) |
+| CSharp7.cs:107:14:107:15 | m1 | string |
+| CSharp7.cs:107:22:107:23 | m2 | (int, int) |
+| CSharp7.cs:108:16:108:17 | m3 | string |
+| CSharp7.cs:109:13:109:14 | m4 | int |
+| CSharp7.cs:109:17:109:18 | m5 | int |
+| CSharp7.cs:111:13:111:14 | m6 | int |
+| CSharp7.cs:112:14:112:15 | m7 | string |
+| CSharp7.cs:112:23:112:24 | m8 | int |
+| CSharp7.cs:112:31:112:32 | m9 | int |
+| CSharp7.cs:113:13:113:15 | m10 | int |
+| CSharp7.cs:117:13:117:15 | m11 | int |
+| CSharp7.cs:120:16:120:18 | m12 | string |
+| CSharp7.cs:121:16:121:18 | m13 | string |
+| CSharp7.cs:133:19:133:20 | f4 | Func |
+| CSharp7.cs:137:24:137:25 | f5 | Func |
+| CSharp7.cs:149:16:149:16 | a | Action |
+| CSharp7.cs:175:16:175:18 | src | string |
+| CSharp7.cs:180:13:180:17 | sink1 | string |
+| CSharp7.cs:181:13:181:17 | sink2 | string |
+| CSharp7.cs:182:13:182:17 | sink3 | string |
+| CSharp7.cs:190:13:190:14 | v1 | int |
+| CSharp7.cs:191:17:191:18 | r1 | int |
+| CSharp7.cs:192:13:192:17 | array | Int32[] |
+| CSharp7.cs:195:17:195:18 | r2 | int |
+| CSharp7.cs:196:17:196:18 | r3 | int |
+| CSharp7.cs:198:17:198:18 | r4 | int |
+| CSharp7.cs:223:14:223:14 | x | int |
+| CSharp7.cs:224:17:224:17 | y | double |
+| CSharp7.cs:224:32:224:32 | z | bool |
+| CSharp7.cs:232:16:232:16 | o | object |
+| CSharp7.cs:233:22:233:23 | i1 | int |
+| CSharp7.cs:237:30:237:31 | s1 | string |
+| CSharp7.cs:244:27:244:28 | v1 | object |
+| CSharp7.cs:254:39:254:40 | s4 | string |
+| CSharp7.cs:257:22:257:23 | i2 | int |
+| CSharp7.cs:260:22:260:23 | i3 | int |
+| CSharp7.cs:263:25:263:26 | s2 | string |
+| CSharp7.cs:269:22:269:23 | v2 | object |
+| CSharp7.cs:282:13:282:16 | dict | Dictionary |
+| CSharp7.cs:283:13:283:16 | list | IEnumerable<(Int32,String)> |
+| CSharp7.cs:285:23:285:23 | a | int |
+| CSharp7.cs:285:33:285:33 | b | string |
| CSharp7.cs:287:23:287:23 | a | int |
-| CSharp7.cs:287:33:287:33 | b | string |
+| CSharp7.cs:287:30:287:30 | b | string |
| CSharp7.cs:289:23:289:23 | a | int |
-| CSharp7.cs:289:30:289:30 | b | string |
-| CSharp7.cs:291:23:291:23 | a | int |
-| CSharp7.cs:291:26:291:26 | b | string |
-| CSharp7.cs:299:18:299:18 | x | int |
-| CSharp7.cs:299:44:299:44 | y | int |
+| CSharp7.cs:289:26:289:26 | b | string |
+| CSharp7.cs:297:18:297:18 | x | int |
+| CSharp7.cs:297:44:297:44 | y | int |
diff --git a/csharp/ql/test/library-tests/csharp7/PrintAst.expected b/csharp/ql/test/library-tests/csharp7/PrintAst.expected
index 6c5ab237eed..57102165f20 100644
--- a/csharp/ql/test/library-tests/csharp7/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp7/PrintAst.expected
@@ -1,911 +1,911 @@
CSharp7.cs:
-# 7| [Class] Literals
-# 9| 5: [Field] x
+# 5| [Class] Literals
+# 7| 5: [Field] x
+# 7| -1: [TypeMention] int
+# 7| 1: [AssignExpr] ... = ...
+# 7| 0: [FieldAccess] access to field x
+# 7| 1: [IntLiteral] 11
+# 8| 6: [Field] y
+# 8| -1: [TypeMention] int
+# 8| 1: [AssignExpr] ... = ...
+# 8| 0: [FieldAccess] access to field y
+# 8| 1: [IntLiteral] 123456
+# 9| 7: [Field] z
# 9| -1: [TypeMention] int
# 9| 1: [AssignExpr] ... = ...
-# 9| 0: [FieldAccess] access to field x
-# 9| 1: [IntLiteral] 11
-# 10| 6: [Field] y
-# 10| -1: [TypeMention] int
-# 10| 1: [AssignExpr] ... = ...
-# 10| 0: [FieldAccess] access to field y
-# 10| 1: [IntLiteral] 123456
-# 11| 7: [Field] z
-# 11| -1: [TypeMention] int
-# 11| 1: [AssignExpr] ... = ...
-# 11| 0: [FieldAccess] access to field z
-# 11| 1: [IntLiteral] 128
-# 14| [Class] ExpressionBodiedMembers
-# 16| 4: [Field] field
+# 9| 0: [FieldAccess] access to field z
+# 9| 1: [IntLiteral] 128
+# 12| [Class] ExpressionBodiedMembers
+# 14| 4: [Field] field
+# 14| -1: [TypeMention] int
+# 14| 1: [AssignExpr] ... = ...
+# 14| 0: [FieldAccess] access to field field
+# 14| 1: [IntLiteral] 0
+# 15| 5: [Method] Foo
+# 15| -1: [TypeMention] int
+# 15| 4: [FieldAccess] access to field field
+# 16| 6: [Property] P
# 16| -1: [TypeMention] int
-# 16| 1: [AssignExpr] ... = ...
-# 16| 0: [FieldAccess] access to field field
-# 16| 1: [IntLiteral] 0
-# 17| 5: [Method] Foo
+# 16| 3: [Getter] get_P
+# 16| 4: [IntLiteral] 5
+# 17| 7: [Property] Q
# 17| -1: [TypeMention] int
-# 17| 4: [FieldAccess] access to field field
-# 18| 6: [Property] P
-# 18| -1: [TypeMention] int
-# 18| 3: [Getter] get_P
-# 18| 4: [IntLiteral] 5
-# 19| 7: [Property] Q
-# 19| -1: [TypeMention] int
-# 21| 3: [Getter] get_Q
-# 21| 4: [MethodCall] call to method Foo
-# 22| 4: [Setter] set_Q
+# 19| 3: [Getter] get_Q
+# 19| 4: [MethodCall] call to method Foo
+# 20| 4: [Setter] set_Q
#-----| 2: (Parameters)
-# 22| 0: [Parameter] value
-# 22| 4: [AssignExpr] ... = ...
-# 22| 0: [FieldAccess] access to field field
-# 22| 1: [ParameterAccess] access to parameter value
-# 24| 8: [InstanceConstructor] ExpressionBodiedMembers
-# 24| 3: [ConstructorInitializer] call to constructor ExpressionBodiedMembers
-# 24| 0: [IntLiteral] 1
-# 24| 4: [BlockStmt] {...}
-# 25| 9: [InstanceConstructor] ExpressionBodiedMembers
+# 20| 0: [Parameter] value
+# 20| 4: [AssignExpr] ... = ...
+# 20| 0: [FieldAccess] access to field field
+# 20| 1: [ParameterAccess] access to parameter value
+# 22| 8: [InstanceConstructor] ExpressionBodiedMembers
+# 22| 3: [ConstructorInitializer] call to constructor ExpressionBodiedMembers
+# 22| 0: [IntLiteral] 1
+# 22| 4: [BlockStmt] {...}
+# 23| 9: [InstanceConstructor] ExpressionBodiedMembers
#-----| 2: (Parameters)
-# 25| 0: [Parameter] x
-# 25| -1: [TypeMention] int
-# 25| 4: [MethodCall] call to method Foo
-# 26| 10: [Destructor] ~ExpressionBodiedMembers
-# 26| 4: [MethodCall] call to method Foo
-# 29| [Class] ThrowExpr
-# 31| 5: [Method] Throw
-# 31| -1: [TypeMention] int
+# 23| 0: [Parameter] x
+# 23| -1: [TypeMention] int
+# 23| 4: [MethodCall] call to method Foo
+# 24| 10: [Destructor] ~ExpressionBodiedMembers
+# 24| 4: [MethodCall] call to method Foo
+# 27| [Class] ThrowExpr
+# 29| 5: [Method] Throw
+# 29| -1: [TypeMention] int
#-----| 2: (Parameters)
-# 31| 0: [Parameter] i
-# 31| -1: [TypeMention] int
-# 32| 4: [BlockStmt] {...}
-# 33| 0: [ReturnStmt] return ...;
-# 33| 0: [ConditionalExpr] ... ? ... : ...
-# 33| 0: [GTExpr] ... > ...
-# 33| 0: [ParameterAccess] access to parameter i
-# 33| 1: [IntLiteral] 0
-# 33| 1: [ParameterAccess] access to parameter i
-# 33| 2: [ThrowExpr] throw ...
-# 33| 0: [ObjectCreation] object creation of type ArgumentException
-# 33| -1: [TypeMention] ArgumentException
-# 33| 0: [StringLiteral] "i"
-# 37| [Class] OutVariables
-# 39| 5: [Method] F
-# 39| -1: [TypeMention] Void
+# 29| 0: [Parameter] i
+# 29| -1: [TypeMention] int
+# 30| 4: [BlockStmt] {...}
+# 31| 0: [ReturnStmt] return ...;
+# 31| 0: [ConditionalExpr] ... ? ... : ...
+# 31| 0: [GTExpr] ... > ...
+# 31| 0: [ParameterAccess] access to parameter i
+# 31| 1: [IntLiteral] 0
+# 31| 1: [ParameterAccess] access to parameter i
+# 31| 2: [ThrowExpr] throw ...
+# 31| 0: [ObjectCreation] object creation of type ArgumentException
+# 31| -1: [TypeMention] ArgumentException
+# 31| 0: [StringLiteral] "i"
+# 35| [Class] OutVariables
+# 37| 5: [Method] F
+# 37| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 39| 0: [Parameter] x
-# 39| -1: [TypeMention] string
-# 40| 4: [BlockStmt] {...}
-# 41| 0: [ExprStmt] ...;
-# 41| 0: [AssignExpr] ... = ...
-# 41| 0: [ParameterAccess] access to parameter x
-# 41| 1: [StringLiteral] "tainted"
-# 44| 6: [Method] G
-# 44| -1: [TypeMention] Void
+# 37| 0: [Parameter] x
+# 37| -1: [TypeMention] string
+# 38| 4: [BlockStmt] {...}
+# 39| 0: [ExprStmt] ...;
+# 39| 0: [AssignExpr] ... = ...
+# 39| 0: [ParameterAccess] access to parameter x
+# 39| 1: [StringLiteral] "tainted"
+# 42| 6: [Method] G
+# 42| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 44| 0: [Parameter] x
-# 44| -1: [TypeMention] string
-# 44| 1: [Parameter] y
-# 44| -1: [TypeMention] string
-# 45| 4: [BlockStmt] {...}
-# 46| 0: [ExprStmt] ...;
-# 46| 0: [AssignExpr] ... = ...
-# 46| 0: [ParameterAccess] access to parameter y
-# 46| 1: [ParameterAccess] access to parameter x
-# 49| 7: [Method] G
-# 49| -1: [TypeMention] Void
-# 50| 4: [BlockStmt] {...}
-# 51| 0: [ExprStmt] ...;
-# 51| 0: [MethodCall] call to method F
-# 51| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t1
-# 52| 1: [ExprStmt] ...;
+# 42| 0: [Parameter] x
+# 42| -1: [TypeMention] string
+# 42| 1: [Parameter] y
+# 42| -1: [TypeMention] string
+# 43| 4: [BlockStmt] {...}
+# 44| 0: [ExprStmt] ...;
+# 44| 0: [AssignExpr] ... = ...
+# 44| 0: [ParameterAccess] access to parameter y
+# 44| 1: [ParameterAccess] access to parameter x
+# 47| 7: [Method] G
+# 47| -1: [TypeMention] Void
+# 48| 4: [BlockStmt] {...}
+# 49| 0: [ExprStmt] ...;
+# 49| 0: [MethodCall] call to method F
+# 49| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t1
+# 50| 1: [ExprStmt] ...;
+# 50| 0: [MethodCall] call to method F
+# 50| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t2
+# 51| 2: [LocalVariableDeclStmt] ... ...;
+# 51| 0: [LocalVariableDeclAndInitExpr] String t3 = ...
+# 51| -1: [TypeMention] string
+# 51| 0: [LocalVariableAccess] access to local variable t3
+# 51| 1: [LocalVariableAccess] access to local variable t1
+# 52| 3: [ExprStmt] ...;
# 52| 0: [MethodCall] call to method F
-# 52| 0: [LocalVariableAccess,LocalVariableDeclExpr] String t2
-# 53| 2: [LocalVariableDeclStmt] ... ...;
-# 53| 0: [LocalVariableDeclAndInitExpr] String t3 = ...
-# 53| -1: [TypeMention] string
+# 52| 0: [LocalVariableAccess] access to local variable t1
+# 53| 4: [ExprStmt] ...;
+# 53| 0: [AssignExpr] ... = ...
# 53| 0: [LocalVariableAccess] access to local variable t3
# 53| 1: [LocalVariableAccess] access to local variable t1
-# 54| 3: [ExprStmt] ...;
-# 54| 0: [MethodCall] call to method F
-# 54| 0: [LocalVariableAccess] access to local variable t1
-# 55| 4: [ExprStmt] ...;
-# 55| 0: [AssignExpr] ... = ...
-# 55| 0: [LocalVariableAccess] access to local variable t3
-# 55| 1: [LocalVariableAccess] access to local variable t1
-# 56| 5: [ExprStmt] ...;
-# 56| 0: [AssignExpr] ... = ...
-# 56| 0: [LocalVariableAccess] access to local variable t3
-# 56| 1: [LocalVariableAccess] access to local variable t2
-# 57| 6: [ExprStmt] ...;
-# 57| 0: [MethodCall] call to method G
-# 57| 0: [StringLiteral] "tainted"
-# 57| 1: [LocalVariableAccess,LocalVariableDeclExpr] String t4
-# 58| 7: [LocalVariableDeclStmt] ... ...;
-# 58| 0: [LocalVariableDeclAndInitExpr] String t5 = ...
-# 58| -1: [TypeMention] string
-# 58| 0: [LocalVariableAccess] access to local variable t5
-# 58| 1: [LocalVariableAccess] access to local variable t4
-# 62| [Class] Tuples
-# 64| 5: [Method] F
-# 64| -1: [TypeMention] (int, int)
-# 64| 1: [TypeMention] int
-# 64| 2: [TypeMention] int
-# 65| 4: [BlockStmt] {...}
-# 66| 0: [ReturnStmt] return ...;
-# 66| 0: [TupleExpr] (..., ...)
-# 66| 0: [IntLiteral] 1
-# 66| 1: [IntLiteral] 2
-# 69| 6: [Method] Expressions
-# 69| -1: [TypeMention] Void
-# 70| 4: [BlockStmt] {...}
-# 71| 0: [ExprStmt] ...;
+# 54| 5: [ExprStmt] ...;
+# 54| 0: [AssignExpr] ... = ...
+# 54| 0: [LocalVariableAccess] access to local variable t3
+# 54| 1: [LocalVariableAccess] access to local variable t2
+# 55| 6: [ExprStmt] ...;
+# 55| 0: [MethodCall] call to method G
+# 55| 0: [StringLiteral] "tainted"
+# 55| 1: [LocalVariableAccess,LocalVariableDeclExpr] String t4
+# 56| 7: [LocalVariableDeclStmt] ... ...;
+# 56| 0: [LocalVariableDeclAndInitExpr] String t5 = ...
+# 56| -1: [TypeMention] string
+# 56| 0: [LocalVariableAccess] access to local variable t5
+# 56| 1: [LocalVariableAccess] access to local variable t4
+# 60| [Class] Tuples
+# 62| 5: [Method] F
+# 62| -1: [TypeMention] (int, int)
+# 62| 1: [TypeMention] int
+# 62| 2: [TypeMention] int
+# 63| 4: [BlockStmt] {...}
+# 64| 0: [ReturnStmt] return ...;
+# 64| 0: [TupleExpr] (..., ...)
+# 64| 0: [IntLiteral] 1
+# 64| 1: [IntLiteral] 2
+# 67| 6: [Method] Expressions
+# 67| -1: [TypeMention] Void
+# 68| 4: [BlockStmt] {...}
+# 69| 0: [ExprStmt] ...;
+# 69| 0: [AssignExpr] ... = ...
+# 69| 0: [TupleExpr] (..., ...)
+# 69| 0: [LocalVariableDeclExpr] Int32 x
+# 69| 1: [LocalVariableDeclExpr] Int32 y
+# 69| 1: [MethodCall] call to method F
+# 70| 1: [LocalVariableDeclStmt] ... ...;
+# 70| 0: [LocalVariableDeclAndInitExpr] (Int32,Int32) z = ...
+# 70| -1: [TypeMention] (int, int)
+# 70| 0: [LocalVariableAccess] access to local variable z
+# 70| 1: [MethodCall] call to method F
+# 71| 2: [ExprStmt] ...;
# 71| 0: [AssignExpr] ... = ...
# 71| 0: [TupleExpr] (..., ...)
-# 71| 0: [LocalVariableDeclExpr] Int32 x
-# 71| 1: [LocalVariableDeclExpr] Int32 y
+# 71| 0: [LocalVariableAccess] access to local variable x
+# 71| 1: [LocalVariableAccess] access to local variable y
# 71| 1: [MethodCall] call to method F
-# 72| 1: [LocalVariableDeclStmt] ... ...;
-# 72| 0: [LocalVariableDeclAndInitExpr] (Int32,Int32) z = ...
-# 72| -1: [TypeMention] (int, int)
-# 72| 0: [LocalVariableAccess] access to local variable z
-# 72| 1: [MethodCall] call to method F
-# 73| 2: [ExprStmt] ...;
+# 72| 3: [ExprStmt] ...;
+# 72| 0: [AssignExpr] ... = ...
+# 72| 0: [LocalVariableAccess] access to local variable x
+# 72| 1: [FieldAccess] access to field Item1
+# 72| -1: [MethodCall] call to method F
+# 73| 4: [ExprStmt] ...;
# 73| 0: [AssignExpr] ... = ...
# 73| 0: [TupleExpr] (..., ...)
# 73| 0: [LocalVariableAccess] access to local variable x
# 73| 1: [LocalVariableAccess] access to local variable y
-# 73| 1: [MethodCall] call to method F
-# 74| 3: [ExprStmt] ...;
+# 73| 2: [FieldAccess] access to field Item1
+# 73| -1: [LocalVariableAccess] access to local variable z
+# 73| 1: [TupleExpr] (..., ...)
+# 73| 0: [IntLiteral] 1
+# 73| 1: [IntLiteral] 2
+# 73| 2: [IntLiteral] 3
+# 74| 5: [ExprStmt] ...;
# 74| 0: [AssignExpr] ... = ...
-# 74| 0: [LocalVariableAccess] access to local variable x
-# 74| 1: [FieldAccess] access to field Item1
-# 74| -1: [MethodCall] call to method F
-# 75| 4: [ExprStmt] ...;
+# 74| 0: [TupleExpr] (..., ...)
+# 74| 0: [LocalVariableAccess] access to local variable x
+# 74| 1: [LocalVariableAccess] access to local variable y
+# 74| 1: [AssignExpr] ... = ...
+# 74| 0: [TupleExpr] (..., ...)
+# 74| 0: [LocalVariableAccess] access to local variable x
+# 74| 1: [LocalVariableAccess] access to local variable y
+# 74| 1: [TupleExpr] (..., ...)
+# 74| 0: [IntLiteral] 1
+# 74| 1: [IntLiteral] 2
+# 75| 6: [ExprStmt] ...;
# 75| 0: [AssignExpr] ... = ...
# 75| 0: [TupleExpr] (..., ...)
-# 75| 0: [LocalVariableAccess] access to local variable x
-# 75| 1: [LocalVariableAccess] access to local variable y
-# 75| 2: [FieldAccess] access to field Item1
-# 75| -1: [LocalVariableAccess] access to local variable z
+# 75| 0: [LocalVariableDeclExpr] Int32 a
+# 75| 1: [TupleExpr] (..., ...)
+# 75| 0: [LocalVariableDeclExpr] Int32 b
+# 75| 1: [LocalVariableDeclExpr] Int32 c
# 75| 1: [TupleExpr] (..., ...)
# 75| 0: [IntLiteral] 1
-# 75| 1: [IntLiteral] 2
-# 75| 2: [IntLiteral] 3
-# 76| 5: [ExprStmt] ...;
+# 75| 1: [LocalVariableAccess] access to local variable z
+# 76| 7: [ExprStmt] ...;
# 76| 0: [AssignExpr] ... = ...
# 76| 0: [TupleExpr] (..., ...)
-# 76| 0: [LocalVariableAccess] access to local variable x
-# 76| 1: [LocalVariableAccess] access to local variable y
-# 76| 1: [AssignExpr] ... = ...
-# 76| 0: [TupleExpr] (..., ...)
-# 76| 0: [LocalVariableAccess] access to local variable x
-# 76| 1: [LocalVariableAccess] access to local variable y
+# 76| 0: [LocalVariableAccess] access to local variable a
# 76| 1: [TupleExpr] (..., ...)
-# 76| 0: [IntLiteral] 1
-# 76| 1: [IntLiteral] 2
-# 77| 6: [ExprStmt] ...;
+# 76| 0: [LocalVariableAccess] access to local variable b
+# 76| 1: [LocalVariableAccess] access to local variable c
+# 76| 1: [TupleExpr] (..., ...)
+# 76| 0: [LocalVariableAccess] access to local variable b
+# 76| 1: [TupleExpr] (..., ...)
+# 76| 0: [LocalVariableAccess] access to local variable c
+# 76| 1: [LocalVariableAccess] access to local variable a
+# 77| 8: [ExprStmt] ...;
# 77| 0: [AssignExpr] ... = ...
# 77| 0: [TupleExpr] (..., ...)
-# 77| 0: [LocalVariableDeclExpr] Int32 a
-# 77| 1: [TupleExpr] (..., ...)
-# 77| 0: [LocalVariableDeclExpr] Int32 b
-# 77| 1: [LocalVariableDeclExpr] Int32 c
+# 77| 0: [LocalVariableDeclExpr] String i
+# 77| 1: [LocalVariableDeclExpr] Int32 j
# 77| 1: [TupleExpr] (..., ...)
-# 77| 0: [IntLiteral] 1
-# 77| 1: [LocalVariableAccess] access to local variable z
-# 78| 7: [ExprStmt] ...;
-# 78| 0: [AssignExpr] ... = ...
-# 78| 0: [TupleExpr] (..., ...)
-# 78| 0: [LocalVariableAccess] access to local variable a
-# 78| 1: [TupleExpr] (..., ...)
-# 78| 0: [LocalVariableAccess] access to local variable b
-# 78| 1: [LocalVariableAccess] access to local variable c
-# 78| 1: [TupleExpr] (..., ...)
-# 78| 0: [LocalVariableAccess] access to local variable b
-# 78| 1: [TupleExpr] (..., ...)
-# 78| 0: [LocalVariableAccess] access to local variable c
-# 78| 1: [LocalVariableAccess] access to local variable a
-# 79| 8: [ExprStmt] ...;
-# 79| 0: [AssignExpr] ... = ...
-# 79| 0: [TupleExpr] (..., ...)
-# 79| 0: [LocalVariableDeclExpr] String i
-# 79| 1: [LocalVariableDeclExpr] Int32 j
-# 79| 1: [TupleExpr] (..., ...)
-# 79| 0: [StringLiteral] ""
-# 79| 1: [LocalVariableAccess] access to local variable x
-# 82| 7: [Method] I
-# 82| -1: [TypeMention] string
+# 77| 0: [StringLiteral] ""
+# 77| 1: [LocalVariableAccess] access to local variable x
+# 80| 7: [Method] I
+# 80| -1: [TypeMention] string
#-----| 2: (Parameters)
-# 82| 0: [Parameter] x
-# 82| -1: [TypeMention] string
-# 83| 4: [BlockStmt] {...}
-# 84| 0: [ReturnStmt] return ...;
-# 84| 0: [FieldAccess] access to field Item1
-# 84| -1: [TupleExpr] (..., ...)
-# 84| 0: [ParameterAccess] access to parameter x
-# 84| 1: [IntLiteral] 2
-# 87| 8: [Method] TaintFlow
-# 87| -1: [TypeMention] Void
-# 88| 4: [BlockStmt] {...}
-# 89| 0: [LocalVariableDeclStmt] ... ...;
-# 89| 0: [LocalVariableDeclAndInitExpr] (String,String) t1 = ...
-# 89| -1: [TypeMention] (string, string)
-# 89| 0: [LocalVariableAccess] access to local variable t1
-# 89| 1: [TupleExpr] (..., ...)
-# 89| 0: [StringLiteral] "tainted"
-# 89| 1: [StringLiteral] "X2"
-# 90| 1: [ExprStmt] ...;
-# 90| 0: [AssignExpr] ... = ...
-# 90| 0: [TupleExpr] (..., ...)
-# 90| 0: [LocalVariableDeclExpr] String t2
-# 90| 1: [LocalVariableDeclExpr] String t3
-# 90| 1: [LocalVariableAccess] access to local variable t1
-# 91| 2: [LocalVariableDeclStmt] ... ...;
-# 91| 0: [LocalVariableDeclAndInitExpr] String t4 = ...
-# 91| -1: [TypeMention] string
-# 91| 0: [LocalVariableAccess] access to local variable t4
-# 91| 1: [LocalVariableAccess] access to local variable t3
-# 92| 3: [LocalVariableDeclStmt] ... ...;
-# 92| 0: [LocalVariableDeclAndInitExpr] String t5 = ...
-# 92| -1: [TypeMention] string
-# 92| 0: [LocalVariableAccess] access to local variable t5
-# 92| 1: [MethodCall] call to method I
-# 92| 0: [FieldAccess] access to field Item1
-# 92| -1: [LocalVariableAccess] access to local variable t1
-# 95| 9: [Method] TupleExprNode
-# 95| -1: [TypeMention] Void
-# 96| 4: [BlockStmt] {...}
-# 97| 0: [LocalVariableDeclStmt] ... ...;
-# 97| 0: [LocalVariableDeclAndInitExpr] (Int32,String) m1 = ...
-# 97| -1: [TypeMention] (int, string)
-# 97| 0: [LocalVariableAccess] access to local variable m1
-# 97| 1: [TupleExpr] (..., ...)
-# 97| 0: [IntLiteral] 1
-# 97| 1: [StringLiteral] "TupleExprNode1"
-# 98| 1: [LocalVariableDeclStmt] ... ...;
-# 98| 0: [LocalVariableDeclAndInitExpr] (Int32,(String,Int32)) m2 = ...
-# 98| -1: [TypeMention] (int, (string, int))
-# 98| 0: [LocalVariableAccess] access to local variable m2
-# 98| 1: [TupleExpr] (..., ...)
-# 98| 0: [IntLiteral] 1
-# 98| 1: [TupleExpr] (..., ...)
-# 98| 0: [StringLiteral] "TupleExprNode2"
-# 98| 1: [IntLiteral] 2
-# 101| 10: [Method] TupleMemberAccess
-# 101| -1: [TypeMention] Void
-# 102| 4: [BlockStmt] {...}
-# 103| 0: [LocalVariableDeclStmt] ... ...;
-# 103| 0: [LocalVariableDeclAndInitExpr] String m1 = ...
-# 103| -1: [TypeMention] string
-# 103| 0: [LocalVariableAccess] access to local variable m1
-# 103| 1: [FieldAccess] access to field Item1
-# 103| -1: [TupleExpr] (..., ...)
-# 103| 0: [StringLiteral] "TupleMemberAccess1"
-# 103| 1: [IntLiteral] 0
-# 104| 1: [LocalVariableDeclStmt] ... ...;
-# 104| 0: [LocalVariableDeclAndInitExpr] (String,Int32) m2 = ...
-# 104| -1: [TypeMention] (string, int)
-# 104| 0: [LocalVariableAccess] access to local variable m2
-# 104| 1: [FieldAccess] access to field Item2
-# 104| -1: [TupleExpr] (..., ...)
-# 104| 0: [IntLiteral] 0
-# 104| 1: [TupleExpr] (..., ...)
-# 104| 0: [StringLiteral] "TupleMemberAccess2"
-# 104| 1: [IntLiteral] 1
-# 107| 11: [Method] DefUse
-# 107| -1: [TypeMention] Void
-# 108| 4: [BlockStmt] {...}
-# 109| 0: [ExprStmt] ...;
-# 109| 0: [AssignExpr] ... = ...
-# 109| 0: [TupleExpr] (..., ...)
-# 109| 0: [LocalVariableDeclExpr] String m1
-# 109| 1: [LocalVariableDeclExpr] (Int32,Int32) m2
-# 109| 1: [TupleExpr] (..., ...)
-# 109| 0: [StringLiteral] "DefUse1"
-# 109| 1: [TupleExpr] (..., ...)
-# 109| 0: [IntLiteral] 0
-# 109| 1: [IntLiteral] 1
-# 110| 1: [LocalVariableDeclStmt] ... ...;
-# 110| 0: [LocalVariableDeclExpr] String m3
-# 110| 0: [TypeMention] string
-# 111| 2: [LocalVariableDeclStmt] ... ...;
-# 111| 0: [LocalVariableDeclExpr] Int32 m4
-# 111| 0: [TypeMention] int
-# 111| 1: [LocalVariableDeclExpr] Int32 m5
-# 111| 0: [TypeMention] int
-# 112| 3: [ExprStmt] ...;
+# 80| 0: [Parameter] x
+# 80| -1: [TypeMention] string
+# 81| 4: [BlockStmt] {...}
+# 82| 0: [ReturnStmt] return ...;
+# 82| 0: [FieldAccess] access to field Item1
+# 82| -1: [TupleExpr] (..., ...)
+# 82| 0: [ParameterAccess] access to parameter x
+# 82| 1: [IntLiteral] 2
+# 85| 8: [Method] TaintFlow
+# 85| -1: [TypeMention] Void
+# 86| 4: [BlockStmt] {...}
+# 87| 0: [LocalVariableDeclStmt] ... ...;
+# 87| 0: [LocalVariableDeclAndInitExpr] (String,String) t1 = ...
+# 87| -1: [TypeMention] (string, string)
+# 87| 0: [LocalVariableAccess] access to local variable t1
+# 87| 1: [TupleExpr] (..., ...)
+# 87| 0: [StringLiteral] "tainted"
+# 87| 1: [StringLiteral] "X2"
+# 88| 1: [ExprStmt] ...;
+# 88| 0: [AssignExpr] ... = ...
+# 88| 0: [TupleExpr] (..., ...)
+# 88| 0: [LocalVariableDeclExpr] String t2
+# 88| 1: [LocalVariableDeclExpr] String t3
+# 88| 1: [LocalVariableAccess] access to local variable t1
+# 89| 2: [LocalVariableDeclStmt] ... ...;
+# 89| 0: [LocalVariableDeclAndInitExpr] String t4 = ...
+# 89| -1: [TypeMention] string
+# 89| 0: [LocalVariableAccess] access to local variable t4
+# 89| 1: [LocalVariableAccess] access to local variable t3
+# 90| 3: [LocalVariableDeclStmt] ... ...;
+# 90| 0: [LocalVariableDeclAndInitExpr] String t5 = ...
+# 90| -1: [TypeMention] string
+# 90| 0: [LocalVariableAccess] access to local variable t5
+# 90| 1: [MethodCall] call to method I
+# 90| 0: [FieldAccess] access to field Item1
+# 90| -1: [LocalVariableAccess] access to local variable t1
+# 93| 9: [Method] TupleExprNode
+# 93| -1: [TypeMention] Void
+# 94| 4: [BlockStmt] {...}
+# 95| 0: [LocalVariableDeclStmt] ... ...;
+# 95| 0: [LocalVariableDeclAndInitExpr] (Int32,String) m1 = ...
+# 95| -1: [TypeMention] (int, string)
+# 95| 0: [LocalVariableAccess] access to local variable m1
+# 95| 1: [TupleExpr] (..., ...)
+# 95| 0: [IntLiteral] 1
+# 95| 1: [StringLiteral] "TupleExprNode1"
+# 96| 1: [LocalVariableDeclStmt] ... ...;
+# 96| 0: [LocalVariableDeclAndInitExpr] (Int32,(String,Int32)) m2 = ...
+# 96| -1: [TypeMention] (int, (string, int))
+# 96| 0: [LocalVariableAccess] access to local variable m2
+# 96| 1: [TupleExpr] (..., ...)
+# 96| 0: [IntLiteral] 1
+# 96| 1: [TupleExpr] (..., ...)
+# 96| 0: [StringLiteral] "TupleExprNode2"
+# 96| 1: [IntLiteral] 2
+# 99| 10: [Method] TupleMemberAccess
+# 99| -1: [TypeMention] Void
+# 100| 4: [BlockStmt] {...}
+# 101| 0: [LocalVariableDeclStmt] ... ...;
+# 101| 0: [LocalVariableDeclAndInitExpr] String m1 = ...
+# 101| -1: [TypeMention] string
+# 101| 0: [LocalVariableAccess] access to local variable m1
+# 101| 1: [FieldAccess] access to field Item1
+# 101| -1: [TupleExpr] (..., ...)
+# 101| 0: [StringLiteral] "TupleMemberAccess1"
+# 101| 1: [IntLiteral] 0
+# 102| 1: [LocalVariableDeclStmt] ... ...;
+# 102| 0: [LocalVariableDeclAndInitExpr] (String,Int32) m2 = ...
+# 102| -1: [TypeMention] (string, int)
+# 102| 0: [LocalVariableAccess] access to local variable m2
+# 102| 1: [FieldAccess] access to field Item2
+# 102| -1: [TupleExpr] (..., ...)
+# 102| 0: [IntLiteral] 0
+# 102| 1: [TupleExpr] (..., ...)
+# 102| 0: [StringLiteral] "TupleMemberAccess2"
+# 102| 1: [IntLiteral] 1
+# 105| 11: [Method] DefUse
+# 105| -1: [TypeMention] Void
+# 106| 4: [BlockStmt] {...}
+# 107| 0: [ExprStmt] ...;
+# 107| 0: [AssignExpr] ... = ...
+# 107| 0: [TupleExpr] (..., ...)
+# 107| 0: [LocalVariableDeclExpr] String m1
+# 107| 1: [LocalVariableDeclExpr] (Int32,Int32) m2
+# 107| 1: [TupleExpr] (..., ...)
+# 107| 0: [StringLiteral] "DefUse1"
+# 107| 1: [TupleExpr] (..., ...)
+# 107| 0: [IntLiteral] 0
+# 107| 1: [IntLiteral] 1
+# 108| 1: [LocalVariableDeclStmt] ... ...;
+# 108| 0: [LocalVariableDeclExpr] String m3
+# 108| 0: [TypeMention] string
+# 109| 2: [LocalVariableDeclStmt] ... ...;
+# 109| 0: [LocalVariableDeclExpr] Int32 m4
+# 109| 0: [TypeMention] int
+# 109| 1: [LocalVariableDeclExpr] Int32 m5
+# 109| 0: [TypeMention] int
+# 110| 3: [ExprStmt] ...;
+# 110| 0: [AssignExpr] ... = ...
+# 110| 0: [TupleExpr] (..., ...)
+# 110| 0: [LocalVariableAccess] access to local variable m3
+# 110| 1: [TupleExpr] (..., ...)
+# 110| 0: [LocalVariableAccess] access to local variable m4
+# 110| 1: [LocalVariableAccess] access to local variable m5
+# 110| 1: [TupleExpr] (..., ...)
+# 110| 0: [LocalVariableAccess] access to local variable m1
+# 110| 1: [LocalVariableAccess] access to local variable m2
+# 111| 4: [LocalVariableDeclStmt] ... ...;
+# 111| 0: [LocalVariableDeclAndInitExpr] Int32 m6 = ...
+# 111| -1: [TypeMention] int
+# 111| 0: [LocalVariableAccess] access to local variable m6
+# 111| 1: [LocalVariableAccess] access to local variable m4
+# 112| 5: [ExprStmt] ...;
# 112| 0: [AssignExpr] ... = ...
# 112| 0: [TupleExpr] (..., ...)
-# 112| 0: [LocalVariableAccess] access to local variable m3
+# 112| 0: [LocalVariableDeclExpr] String m7
# 112| 1: [TupleExpr] (..., ...)
-# 112| 0: [LocalVariableAccess] access to local variable m4
-# 112| 1: [LocalVariableAccess] access to local variable m5
-# 112| 1: [TupleExpr] (..., ...)
-# 112| 0: [LocalVariableAccess] access to local variable m1
-# 112| 1: [LocalVariableAccess] access to local variable m2
-# 113| 4: [LocalVariableDeclStmt] ... ...;
-# 113| 0: [LocalVariableDeclAndInitExpr] Int32 m6 = ...
+# 112| 0: [LocalVariableDeclExpr] Int32 m8
+# 112| 1: [LocalVariableDeclExpr] Int32 m9
+# 112| 1: [AssignExpr] ... = ...
+# 112| 0: [TupleExpr] (..., ...)
+# 112| 0: [LocalVariableAccess] access to local variable m1
+# 112| 1: [LocalVariableAccess] access to local variable m2
+# 112| 1: [TupleExpr] (..., ...)
+# 112| 0: [StringLiteral] "DefUse2"
+# 112| 1: [TupleExpr] (..., ...)
+# 112| 0: [IntLiteral] 0
+# 112| 1: [IntLiteral] 1
+# 113| 6: [LocalVariableDeclStmt] ... ...;
+# 113| 0: [LocalVariableDeclAndInitExpr] Int32 m10 = ...
# 113| -1: [TypeMention] int
-# 113| 0: [LocalVariableAccess] access to local variable m6
-# 113| 1: [LocalVariableAccess] access to local variable m4
-# 114| 5: [ExprStmt] ...;
-# 114| 0: [AssignExpr] ... = ...
-# 114| 0: [TupleExpr] (..., ...)
-# 114| 0: [LocalVariableDeclExpr] String m7
-# 114| 1: [TupleExpr] (..., ...)
-# 114| 0: [LocalVariableDeclExpr] Int32 m8
-# 114| 1: [LocalVariableDeclExpr] Int32 m9
-# 114| 1: [AssignExpr] ... = ...
-# 114| 0: [TupleExpr] (..., ...)
-# 114| 0: [LocalVariableAccess] access to local variable m1
-# 114| 1: [LocalVariableAccess] access to local variable m2
-# 114| 1: [TupleExpr] (..., ...)
-# 114| 0: [StringLiteral] "DefUse2"
-# 114| 1: [TupleExpr] (..., ...)
-# 114| 0: [IntLiteral] 0
-# 114| 1: [IntLiteral] 1
-# 115| 6: [LocalVariableDeclStmt] ... ...;
-# 115| 0: [LocalVariableDeclAndInitExpr] Int32 m10 = ...
-# 115| -1: [TypeMention] int
-# 115| 0: [LocalVariableAccess] access to local variable m10
-# 115| 1: [LocalVariableAccess] access to local variable m9
-# 118| 7: [ExprStmt] ...;
-# 118| 0: [AssignExpr] ... = ...
-# 118| 0: [FieldAccess] access to field Item2
-# 118| -1: [LocalVariableAccess] access to local variable m2
-# 118| 1: [IntLiteral] 0
-# 119| 8: [LocalVariableDeclStmt] ... ...;
-# 119| 0: [LocalVariableDeclAndInitExpr] Int32 m11 = ...
-# 119| -1: [TypeMention] int
-# 119| 0: [LocalVariableAccess] access to local variable m11
-# 119| 1: [FieldAccess] access to field Item1
-# 119| -1: [LocalVariableAccess] access to local variable m2
-# 122| 9: [LocalVariableDeclStmt] ... ...;
-# 122| 0: [LocalVariableDeclExpr] String m12
-# 122| 0: [TypeMention] string
-# 123| 10: [LocalVariableDeclStmt] ... ...;
-# 123| 0: [LocalVariableDeclAndInitExpr] String m13 = ...
-# 123| -1: [TypeMention] string
-# 123| 0: [LocalVariableAccess] access to local variable m13
-# 123| 1: [AssignExpr] ... = ...
-# 123| 0: [LocalVariableAccess] access to local variable m12
-# 123| 1: [StringLiteral] "DefUse3"
-# 127| [Class] LocalFunctions
-# 129| 5: [Method] Main
-# 129| -1: [TypeMention] int
-# 130| 4: [BlockStmt] {...}
-# 131| 0: [LocalFunctionStmt] f1(...)
-# 131| 0: [LocalFunction] f1
+# 113| 0: [LocalVariableAccess] access to local variable m10
+# 113| 1: [LocalVariableAccess] access to local variable m9
+# 116| 7: [ExprStmt] ...;
+# 116| 0: [AssignExpr] ... = ...
+# 116| 0: [FieldAccess] access to field Item2
+# 116| -1: [LocalVariableAccess] access to local variable m2
+# 116| 1: [IntLiteral] 0
+# 117| 8: [LocalVariableDeclStmt] ... ...;
+# 117| 0: [LocalVariableDeclAndInitExpr] Int32 m11 = ...
+# 117| -1: [TypeMention] int
+# 117| 0: [LocalVariableAccess] access to local variable m11
+# 117| 1: [FieldAccess] access to field Item1
+# 117| -1: [LocalVariableAccess] access to local variable m2
+# 120| 9: [LocalVariableDeclStmt] ... ...;
+# 120| 0: [LocalVariableDeclExpr] String m12
+# 120| 0: [TypeMention] string
+# 121| 10: [LocalVariableDeclStmt] ... ...;
+# 121| 0: [LocalVariableDeclAndInitExpr] String m13 = ...
+# 121| -1: [TypeMention] string
+# 121| 0: [LocalVariableAccess] access to local variable m13
+# 121| 1: [AssignExpr] ... = ...
+# 121| 0: [LocalVariableAccess] access to local variable m12
+# 121| 1: [StringLiteral] "DefUse3"
+# 125| [Class] LocalFunctions
+# 127| 5: [Method] Main
+# 127| -1: [TypeMention] int
+# 128| 4: [BlockStmt] {...}
+# 129| 0: [LocalFunctionStmt] f1(...)
+# 129| 0: [LocalFunction] f1
#-----| 2: (Parameters)
-# 131| 0: [Parameter] x
-# 131| -1: [TypeMention] int
+# 129| 0: [Parameter] x
+# 129| -1: [TypeMention] int
+# 129| 4: [BlockStmt] {...}
+# 129| 0: [ReturnStmt] return ...;
+# 129| 0: [AddExpr] ... + ...
+# 129| 0: [ParameterAccess] access to parameter x
+# 129| 1: [IntLiteral] 1
+# 131| 1: [LocalFunctionStmt] f2(...)
+# 131| 0: [LocalFunction] f2
+#-----| 1: (Type parameters)
+# 131| 0: [TypeParameter] T
+# 131| 1: [TypeParameter] U
+#-----| 2: (Parameters)
+# 131| 0: [Parameter] t
+# 131| -1: [TypeMention] T
+# 131| 1: [Parameter] u
+# 131| -1: [TypeMention] U
# 131| 4: [BlockStmt] {...}
# 131| 0: [ReturnStmt] return ...;
-# 131| 0: [AddExpr] ... + ...
-# 131| 0: [ParameterAccess] access to parameter x
-# 131| 1: [IntLiteral] 1
-# 133| 1: [LocalFunctionStmt] f2(...)
-# 133| 0: [LocalFunction] f2
-#-----| 1: (Type parameters)
-# 133| 0: [TypeParameter] T
-# 133| 1: [TypeParameter] U
-#-----| 2: (Parameters)
-# 133| 0: [Parameter] t
-# 133| -1: [TypeMention] T
-# 133| 1: [Parameter] u
-# 133| -1: [TypeMention] U
-# 133| 4: [BlockStmt] {...}
-# 133| 0: [ReturnStmt] return ...;
-# 133| 0: [ParameterAccess] access to parameter t
-# 135| 2: [LocalVariableDeclStmt] ... ...;
-# 135| 0: [LocalVariableDeclAndInitExpr] Func f4 = ...
-# 135| -1: [TypeMention] Func
-# 135| 1: [TypeMention] int
-# 135| 0: [LocalVariableAccess] access to local variable f4
-# 135| 1: [ImplicitDelegateCreation] delegate creation of type Func
-# 135| 0: [LocalFunctionAccess] access to local function f3
-# 137| 3: [LocalFunctionStmt] f3(...)
-# 137| 0: [LocalFunction] f3
-# 137| 4: [IntLiteral] 2
-# 139| 4: [LocalVariableDeclStmt] ... ...;
-# 139| 0: [LocalVariableDeclAndInitExpr] Func f5 = ...
-# 139| -1: [TypeMention] Func
-# 139| 1: [TypeMention] int
-# 139| 2: [TypeMention] int
-# 139| 0: [LocalVariableAccess] access to local variable f5
-# 139| 1: [LambdaExpr] (...) => ...
+# 131| 0: [ParameterAccess] access to parameter t
+# 133| 2: [LocalVariableDeclStmt] ... ...;
+# 133| 0: [LocalVariableDeclAndInitExpr] Func f4 = ...
+# 133| -1: [TypeMention] Func
+# 133| 1: [TypeMention] int
+# 133| 0: [LocalVariableAccess] access to local variable f4
+# 133| 1: [ImplicitDelegateCreation] delegate creation of type Func
+# 133| 0: [LocalFunctionAccess] access to local function f3
+# 135| 3: [LocalFunctionStmt] f3(...)
+# 135| 0: [LocalFunction] f3
+# 135| 4: [IntLiteral] 2
+# 137| 4: [LocalVariableDeclStmt] ... ...;
+# 137| 0: [LocalVariableDeclAndInitExpr] Func f5 = ...
+# 137| -1: [TypeMention] Func
+# 137| 1: [TypeMention] int
+# 137| 2: [TypeMention] int
+# 137| 0: [LocalVariableAccess] access to local variable f5
+# 137| 1: [LambdaExpr] (...) => ...
#-----| 2: (Parameters)
-# 139| 0: [Parameter] x
-# 139| 4: [AddExpr] ... + ...
+# 137| 0: [Parameter] x
+# 137| 4: [AddExpr] ... + ...
+# 137| 0: [ParameterAccess] access to parameter x
+# 137| 1: [IntLiteral] 1
+# 139| 5: [LocalFunctionStmt] f6(...)
+# 139| 0: [LocalFunction] f6
+#-----| 2: (Parameters)
+# 139| 0: [Parameter] x
+# 139| -1: [TypeMention] int
+# 139| 4: [ConditionalExpr] ... ? ... : ...
+# 139| 0: [GTExpr] ... > ...
# 139| 0: [ParameterAccess] access to parameter x
-# 139| 1: [IntLiteral] 1
-# 141| 5: [LocalFunctionStmt] f6(...)
-# 141| 0: [LocalFunction] f6
+# 139| 1: [IntLiteral] 0
+# 139| 1: [AddExpr] ... + ...
+# 139| 0: [IntLiteral] 1
+# 139| 1: [LocalFunctionCall] call to local function f7
+# 139| -1: [LocalFunctionAccess] access to local function f7
+# 139| 0: [SubExpr] ... - ...
+# 139| 0: [ParameterAccess] access to parameter x
+# 139| 1: [IntLiteral] 1
+# 139| 2: [IntLiteral] 0
+# 141| 6: [LocalFunctionStmt] f7(...)
+# 141| 0: [LocalFunction] f7
#-----| 2: (Parameters)
# 141| 0: [Parameter] x
# 141| -1: [TypeMention] int
-# 141| 4: [ConditionalExpr] ... ? ... : ...
-# 141| 0: [GTExpr] ... > ...
-# 141| 0: [ParameterAccess] access to parameter x
-# 141| 1: [IntLiteral] 0
-# 141| 1: [AddExpr] ... + ...
-# 141| 0: [IntLiteral] 1
-# 141| 1: [LocalFunctionCall] call to local function f7
-# 141| -1: [LocalFunctionAccess] access to local function f7
-# 141| 0: [SubExpr] ... - ...
-# 141| 0: [ParameterAccess] access to parameter x
-# 141| 1: [IntLiteral] 1
-# 141| 2: [IntLiteral] 0
-# 143| 6: [LocalFunctionStmt] f7(...)
-# 143| 0: [LocalFunction] f7
-#-----| 2: (Parameters)
-# 143| 0: [Parameter] x
-# 143| -1: [TypeMention] int
-# 143| 4: [LocalFunctionCall] call to local function f6
-# 143| -1: [LocalFunctionAccess] access to local function f6
-# 143| 0: [ParameterAccess] access to parameter x
-# 145| 7: [LocalFunctionStmt] f8(...)
-# 145| 0: [LocalFunction] f8
-# 146| 4: [BlockStmt] {...}
-# 147| 0: [LocalFunctionStmt] f9(...)
-# 147| 0: [LocalFunction] f9
+# 141| 4: [LocalFunctionCall] call to local function f6
+# 141| -1: [LocalFunctionAccess] access to local function f6
+# 141| 0: [ParameterAccess] access to parameter x
+# 143| 7: [LocalFunctionStmt] f8(...)
+# 143| 0: [LocalFunction] f8
+# 144| 4: [BlockStmt] {...}
+# 145| 0: [LocalFunctionStmt] f9(...)
+# 145| 0: [LocalFunction] f9
#-----| 2: (Parameters)
-# 147| 0: [Parameter] x
-# 147| -1: [TypeMention] int
-# 147| 4: [LocalFunctionCall] call to local function f7
-# 147| -1: [LocalFunctionAccess] access to local function f7
-# 147| 0: [ParameterAccess] access to parameter x
-# 148| 1: [ReturnStmt] return ...;
-# 148| 0: [LocalFunctionCall] call to local function f9
-# 148| -1: [LocalFunctionAccess] access to local function f9
-# 148| 0: [IntLiteral] 1
-# 151| 8: [LocalVariableDeclStmt] ... ...;
-# 151| 0: [LocalVariableDeclAndInitExpr] Action a = ...
-# 151| -1: [TypeMention] Action
-# 151| 0: [LocalVariableAccess] access to local variable a
-# 151| 1: [LambdaExpr] (...) => ...
-# 152| 4: [BlockStmt] {...}
-# 153| 0: [LocalFunctionStmt] f9(...)
-# 153| 0: [LocalFunction] f9
-# 153| 4: [IntLiteral] 0
-# 156| 9: [ReturnStmt] return ...;
-# 156| 0: [LocalFunctionCall] call to local function f1
-# 156| -1: [LocalFunctionAccess] access to local function f1
-# 156| 0: [IntLiteral] 2
-# 159| 6: [Method] Generics
-# 159| -1: [TypeMention] Void
-# 160| 4: [BlockStmt] {...}
-# 161| 0: [LocalFunctionStmt] f(...)
-# 161| 0: [LocalFunction] f
+# 145| 0: [Parameter] x
+# 145| -1: [TypeMention] int
+# 145| 4: [LocalFunctionCall] call to local function f7
+# 145| -1: [LocalFunctionAccess] access to local function f7
+# 145| 0: [ParameterAccess] access to parameter x
+# 146| 1: [ReturnStmt] return ...;
+# 146| 0: [LocalFunctionCall] call to local function f9
+# 146| -1: [LocalFunctionAccess] access to local function f9
+# 146| 0: [IntLiteral] 1
+# 149| 8: [LocalVariableDeclStmt] ... ...;
+# 149| 0: [LocalVariableDeclAndInitExpr] Action a = ...
+# 149| -1: [TypeMention] Action
+# 149| 0: [LocalVariableAccess] access to local variable a
+# 149| 1: [LambdaExpr] (...) => ...
+# 150| 4: [BlockStmt] {...}
+# 151| 0: [LocalFunctionStmt] f9(...)
+# 151| 0: [LocalFunction] f9
+# 151| 4: [IntLiteral] 0
+# 154| 9: [ReturnStmt] return ...;
+# 154| 0: [LocalFunctionCall] call to local function f1
+# 154| -1: [LocalFunctionAccess] access to local function f1
+# 154| 0: [IntLiteral] 2
+# 157| 6: [Method] Generics
+# 157| -1: [TypeMention] Void
+# 158| 4: [BlockStmt] {...}
+# 159| 0: [LocalFunctionStmt] f(...)
+# 159| 0: [LocalFunction] f
#-----| 1: (Type parameters)
-# 161| 0: [TypeParameter] T
-# 161| 4: [IntLiteral] 1
-# 162| 1: [LocalFunctionStmt] g(...)
-# 162| 0: [LocalFunction] g
+# 159| 0: [TypeParameter] T
+# 159| 4: [IntLiteral] 1
+# 160| 1: [LocalFunctionStmt] g(...)
+# 160| 0: [LocalFunction] g
+#-----| 1: (Type parameters)
+# 160| 0: [TypeParameter] T
+#-----| 2: (Parameters)
+# 160| 0: [Parameter] t
+# 160| -1: [TypeMention] T
+# 160| 4: [ParameterAccess] access to parameter t
+# 162| 2: [LocalFunctionStmt] h(...)
+# 162| 0: [LocalFunction] h
#-----| 1: (Type parameters)
# 162| 0: [TypeParameter] T
+# 162| 1: [TypeParameter] U
#-----| 2: (Parameters)
# 162| 0: [Parameter] t
# 162| -1: [TypeMention] T
-# 162| 4: [ParameterAccess] access to parameter t
-# 164| 2: [LocalFunctionStmt] h(...)
-# 164| 0: [LocalFunction] h
-#-----| 1: (Type parameters)
-# 164| 0: [TypeParameter] T
-# 164| 1: [TypeParameter] U
-#-----| 2: (Parameters)
-# 164| 0: [Parameter] t
-# 164| -1: [TypeMention] T
-# 164| 1: [Parameter] u
-# 164| -1: [TypeMention] U
-# 165| 4: [BlockStmt] {...}
-# 166| 0: [LocalFunctionStmt] f2(...)
-# 166| 0: [LocalFunction] f2
+# 162| 1: [Parameter] u
+# 162| -1: [TypeMention] U
+# 163| 4: [BlockStmt] {...}
+# 164| 0: [LocalFunctionStmt] f2(...)
+# 164| 0: [LocalFunction] f2
#-----| 1: (Type parameters)
-# 166| 0: [TypeParameter] S
+# 164| 0: [TypeParameter] S
#-----| 2: (Parameters)
-# 166| 0: [Parameter] s
-# 166| -1: [TypeMention] S
-# 166| 1: [Parameter] _t
-# 166| -1: [TypeMention] T
-# 166| 4: [LocalFunctionCall] call to local function f
-# 166| -1: [LocalFunctionAccess] access to local function f
-# 167| 1: [ExprStmt] ...;
-# 167| 0: [LocalFunctionCall] call to local function f
-# 167| -1: [LocalFunctionAccess] access to local function f
-# 168| 2: [ReturnStmt] return ...;
-# 168| 0: [LocalFunctionCall] call to local function g
-# 168| -1: [LocalFunctionAccess] access to local function g
-# 168| 0: [ParameterAccess] access to parameter u
-# 171| 3: [ExprStmt] ...;
-# 171| 0: [LocalFunctionCall] call to local function h
-# 171| -1: [LocalFunctionAccess] access to local function h
-# 171| 0: [IntLiteral] 0
-# 171| 1: [IntLiteral] 0
-# 172| 4: [ExprStmt] ...;
-# 172| 0: [LocalFunctionCall] call to local function h
-# 172| -1: [LocalFunctionAccess] access to local function h
-# 172| 0: [StringLiteral] ""
-# 172| 1: [BoolLiteral] true
-# 175| 7: [Method] GlobalFlow
-# 175| -1: [TypeMention] Void
-# 176| 4: [BlockStmt] {...}
-# 177| 0: [LocalVariableDeclStmt] ... ...;
-# 177| 0: [LocalVariableDeclAndInitExpr] String src = ...
-# 177| -1: [TypeMention] string
-# 177| 0: [LocalVariableAccess] access to local variable src
-# 177| 1: [StringLiteral] "tainted"
-# 178| 1: [LocalFunctionStmt] f(...)
-# 178| 0: [LocalFunction] f
+# 164| 0: [Parameter] s
+# 164| -1: [TypeMention] S
+# 164| 1: [Parameter] _t
+# 164| -1: [TypeMention] T
+# 164| 4: [LocalFunctionCall] call to local function f
+# 164| -1: [LocalFunctionAccess] access to local function f
+# 165| 1: [ExprStmt] ...;
+# 165| 0: [LocalFunctionCall] call to local function f
+# 165| -1: [LocalFunctionAccess] access to local function f
+# 166| 2: [ReturnStmt] return ...;
+# 166| 0: [LocalFunctionCall] call to local function g
+# 166| -1: [LocalFunctionAccess] access to local function g
+# 166| 0: [ParameterAccess] access to parameter u
+# 169| 3: [ExprStmt] ...;
+# 169| 0: [LocalFunctionCall] call to local function h
+# 169| -1: [LocalFunctionAccess] access to local function h
+# 169| 0: [IntLiteral] 0
+# 169| 1: [IntLiteral] 0
+# 170| 4: [ExprStmt] ...;
+# 170| 0: [LocalFunctionCall] call to local function h
+# 170| -1: [LocalFunctionAccess] access to local function h
+# 170| 0: [StringLiteral] ""
+# 170| 1: [BoolLiteral] true
+# 173| 7: [Method] GlobalFlow
+# 173| -1: [TypeMention] Void
+# 174| 4: [BlockStmt] {...}
+# 175| 0: [LocalVariableDeclStmt] ... ...;
+# 175| 0: [LocalVariableDeclAndInitExpr] String src = ...
+# 175| -1: [TypeMention] string
+# 175| 0: [LocalVariableAccess] access to local variable src
+# 175| 1: [StringLiteral] "tainted"
+# 176| 1: [LocalFunctionStmt] f(...)
+# 176| 0: [LocalFunction] f
+#-----| 2: (Parameters)
+# 176| 0: [Parameter] s
+# 176| -1: [TypeMention] string
+# 176| 4: [AddExpr] ... + ...
+# 176| 0: [LocalFunctionCall] call to local function g
+# 176| -1: [LocalFunctionAccess] access to local function g
+# 176| 0: [ParameterAccess] access to parameter s
+# 176| 1: [StringLiteral] ""
+# 177| 2: [LocalFunctionStmt] g(...)
+# 177| 0: [LocalFunction] g
+#-----| 2: (Parameters)
+# 177| 0: [Parameter] s
+# 177| -1: [TypeMention] string
+# 177| 4: [ParameterAccess] access to parameter s
+# 178| 3: [LocalFunctionStmt] h(...)
+# 178| 0: [LocalFunction] h
#-----| 2: (Parameters)
# 178| 0: [Parameter] s
# 178| -1: [TypeMention] string
-# 178| 4: [AddExpr] ... + ...
-# 178| 0: [LocalFunctionCall] call to local function g
-# 178| -1: [LocalFunctionAccess] access to local function g
+# 178| 4: [BlockStmt] {...}
+# 178| 0: [ReturnStmt] return ...;
# 178| 0: [ParameterAccess] access to parameter s
-# 178| 1: [StringLiteral] ""
-# 179| 2: [LocalFunctionStmt] g(...)
-# 179| 0: [LocalFunction] g
-#-----| 2: (Parameters)
-# 179| 0: [Parameter] s
-# 179| -1: [TypeMention] string
-# 179| 4: [ParameterAccess] access to parameter s
-# 180| 3: [LocalFunctionStmt] h(...)
-# 180| 0: [LocalFunction] h
-#-----| 2: (Parameters)
-# 180| 0: [Parameter] s
-# 180| -1: [TypeMention] string
-# 180| 4: [BlockStmt] {...}
-# 180| 0: [ReturnStmt] return ...;
-# 180| 0: [ParameterAccess] access to parameter s
-# 182| 4: [LocalVariableDeclStmt] ... ...;
-# 182| 0: [LocalVariableDeclAndInitExpr] String sink1 = ...
+# 180| 4: [LocalVariableDeclStmt] ... ...;
+# 180| 0: [LocalVariableDeclAndInitExpr] String sink1 = ...
+# 180| -1: [TypeMention] string
+# 180| 0: [LocalVariableAccess] access to local variable sink1
+# 180| 1: [LocalFunctionCall] call to local function f
+# 180| -1: [LocalFunctionAccess] access to local function f
+# 180| 0: [LocalVariableAccess] access to local variable src
+# 181| 5: [LocalVariableDeclStmt] ... ...;
+# 181| 0: [LocalVariableDeclAndInitExpr] String sink2 = ...
+# 181| -1: [TypeMention] string
+# 181| 0: [LocalVariableAccess] access to local variable sink2
+# 181| 1: [LocalFunctionCall] call to local function g
+# 181| -1: [LocalFunctionAccess] access to local function g
+# 181| 0: [LocalVariableAccess] access to local variable src
+# 182| 6: [LocalVariableDeclStmt] ... ...;
+# 182| 0: [LocalVariableDeclAndInitExpr] String sink3 = ...
# 182| -1: [TypeMention] string
-# 182| 0: [LocalVariableAccess] access to local variable sink1
-# 182| 1: [LocalFunctionCall] call to local function f
-# 182| -1: [LocalFunctionAccess] access to local function f
+# 182| 0: [LocalVariableAccess] access to local variable sink3
+# 182| 1: [LocalFunctionCall] call to local function h
+# 182| -1: [LocalFunctionAccess] access to local function h
# 182| 0: [LocalVariableAccess] access to local variable src
-# 183| 5: [LocalVariableDeclStmt] ... ...;
-# 183| 0: [LocalVariableDeclAndInitExpr] String sink2 = ...
-# 183| -1: [TypeMention] string
-# 183| 0: [LocalVariableAccess] access to local variable sink2
-# 183| 1: [LocalFunctionCall] call to local function g
-# 183| -1: [LocalFunctionAccess] access to local function g
-# 183| 0: [LocalVariableAccess] access to local variable src
-# 184| 6: [LocalVariableDeclStmt] ... ...;
-# 184| 0: [LocalVariableDeclAndInitExpr] String sink3 = ...
-# 184| -1: [TypeMention] string
-# 184| 0: [LocalVariableAccess] access to local variable sink3
-# 184| 1: [LocalFunctionCall] call to local function h
-# 184| -1: [LocalFunctionAccess] access to local function h
-# 184| 0: [LocalVariableAccess] access to local variable src
-# 188| [Class] Refs
-# 190| 5: [Method] F1
-# 190| -1: [TypeMention] Void
-# 191| 4: [BlockStmt] {...}
-# 192| 0: [LocalVariableDeclStmt] ... ...;
-# 192| 0: [LocalVariableDeclAndInitExpr] Int32 v1 = ...
-# 192| -1: [TypeMention] int
-# 192| 0: [LocalVariableAccess] access to local variable v1
-# 192| 1: [IntLiteral] 2
-# 193| 1: [LocalVariableDeclStmt] ... ...;
-# 193| 0: [LocalVariableDeclAndInitExpr] Int32 r1 = ...
-# 193| -1: [TypeMention] null
+# 186| [Class] Refs
+# 188| 5: [Method] F1
+# 188| -1: [TypeMention] Void
+# 189| 4: [BlockStmt] {...}
+# 190| 0: [LocalVariableDeclStmt] ... ...;
+# 190| 0: [LocalVariableDeclAndInitExpr] Int32 v1 = ...
+# 190| -1: [TypeMention] int
+# 190| 0: [LocalVariableAccess] access to local variable v1
+# 190| 1: [IntLiteral] 2
+# 191| 1: [LocalVariableDeclStmt] ... ...;
+# 191| 0: [LocalVariableDeclAndInitExpr] Int32 r1 = ...
+# 191| -1: [TypeMention] null
+# 191| 0: [LocalVariableAccess] access to local variable r1
+# 191| 1: [RefExpr] ref ...
+# 191| 0: [LocalVariableAccess] access to local variable v1
+# 192| 2: [LocalVariableDeclStmt] ... ...;
+# 192| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ...
+# 192| -1: [TypeMention] Int32[]
+# 192| 0: [LocalVariableAccess] access to local variable array
+# 192| 1: [ArrayCreation] array creation of type Int32[]
+# 192| -1: [TypeMention] Int32[]
+# 192| 1: [TypeMention] int
+# 192| 0: [IntLiteral] 10
+# 193| 3: [ExprStmt] ...;
+# 193| 0: [AssignExpr] ... = ...
# 193| 0: [LocalVariableAccess] access to local variable r1
-# 193| 1: [RefExpr] ref ...
-# 193| 0: [LocalVariableAccess] access to local variable v1
-# 194| 2: [LocalVariableDeclStmt] ... ...;
-# 194| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ...
-# 194| -1: [TypeMention] Int32[]
-# 194| 0: [LocalVariableAccess] access to local variable array
-# 194| 1: [ArrayCreation] array creation of type Int32[]
-# 194| -1: [TypeMention] Int32[]
-# 194| 1: [TypeMention] int
-# 194| 0: [IntLiteral] 10
-# 195| 3: [ExprStmt] ...;
-# 195| 0: [AssignExpr] ... = ...
-# 195| 0: [LocalVariableAccess] access to local variable r1
-# 195| 1: [IntLiteral] 3
-# 196| 4: [ExprStmt] ...;
-# 196| 0: [AssignExpr] ... = ...
-# 196| 0: [LocalVariableAccess] access to local variable r1
-# 196| 1: [ArrayAccess] access to array element
-# 196| -1: [LocalVariableAccess] access to local variable array
-# 196| 0: [IntLiteral] 1
-# 197| 5: [LocalVariableDeclStmt] ... ...;
-# 197| 0: [LocalVariableDeclAndInitExpr] Int32 r2 = ...
-# 197| -1: [TypeMention] null
-# 197| 0: [LocalVariableAccess] access to local variable r2
-# 197| 1: [RefExpr] ref ...
-# 197| 0: [ArrayAccess] access to array element
-# 197| -1: [LocalVariableAccess] access to local variable array
-# 197| 0: [IntLiteral] 3
-# 198| 6: [LocalVariableDeclStmt] ... ...;
-# 198| 0: [LocalVariableDeclAndInitExpr] Int32 r3 = ...
+# 193| 1: [IntLiteral] 3
+# 194| 4: [ExprStmt] ...;
+# 194| 0: [AssignExpr] ... = ...
+# 194| 0: [LocalVariableAccess] access to local variable r1
+# 194| 1: [ArrayAccess] access to array element
+# 194| -1: [LocalVariableAccess] access to local variable array
+# 194| 0: [IntLiteral] 1
+# 195| 5: [LocalVariableDeclStmt] ... ...;
+# 195| 0: [LocalVariableDeclAndInitExpr] Int32 r2 = ...
+# 195| -1: [TypeMention] null
+# 195| 0: [LocalVariableAccess] access to local variable r2
+# 195| 1: [RefExpr] ref ...
+# 195| 0: [ArrayAccess] access to array element
+# 195| -1: [LocalVariableAccess] access to local variable array
+# 195| 0: [IntLiteral] 3
+# 196| 6: [LocalVariableDeclStmt] ... ...;
+# 196| 0: [LocalVariableDeclAndInitExpr] Int32 r3 = ...
+# 196| -1: [TypeMention] null
+# 196| 0: [LocalVariableAccess] access to local variable r3
+# 196| 1: [RefExpr] ref ...
+# 196| 0: [LocalVariableAccess] access to local variable r1
+# 197| 7: [ExprStmt] ...;
+# 197| 0: [AssignExpr] ... = ...
+# 197| 0: [LocalVariableAccess] access to local variable v1
+# 197| 1: [MethodCall] call to method F2
+# 197| 0: [LocalVariableAccess] access to local variable v1
+# 198| 8: [LocalVariableDeclStmt] ... ...;
+# 198| 0: [LocalVariableDeclAndInitExpr] Int32 r4 = ...
# 198| -1: [TypeMention] null
-# 198| 0: [LocalVariableAccess] access to local variable r3
+# 198| 0: [LocalVariableAccess] access to local variable r4
# 198| 1: [RefExpr] ref ...
-# 198| 0: [LocalVariableAccess] access to local variable r1
-# 199| 7: [ExprStmt] ...;
+# 198| 0: [MethodCall] call to method F2
+# 198| 0: [LocalVariableAccess] access to local variable r1
+# 199| 9: [ExprStmt] ...;
# 199| 0: [AssignExpr] ... = ...
-# 199| 0: [LocalVariableAccess] access to local variable v1
-# 199| 1: [MethodCall] call to method F2
-# 199| 0: [LocalVariableAccess] access to local variable v1
-# 200| 8: [LocalVariableDeclStmt] ... ...;
-# 200| 0: [LocalVariableDeclAndInitExpr] Int32 r4 = ...
-# 200| -1: [TypeMention] null
-# 200| 0: [LocalVariableAccess] access to local variable r4
-# 200| 1: [RefExpr] ref ...
-# 200| 0: [MethodCall] call to method F2
-# 200| 0: [LocalVariableAccess] access to local variable r1
-# 201| 9: [ExprStmt] ...;
-# 201| 0: [AssignExpr] ... = ...
-# 201| 0: [MethodCall] call to method F2
-# 201| 0: [LocalVariableAccess] access to local variable r1
-# 201| 1: [IntLiteral] 3
-# 204| 6: [Method] F2
-# 204| -1: [TypeMention] int
+# 199| 0: [MethodCall] call to method F2
+# 199| 0: [LocalVariableAccess] access to local variable r1
+# 199| 1: [IntLiteral] 3
+# 202| 6: [Method] F2
+# 202| -1: [TypeMention] int
#-----| 2: (Parameters)
-# 204| 0: [Parameter] p
-# 204| -1: [TypeMention] int
-# 205| 4: [BlockStmt] {...}
-# 206| 0: [LocalFunctionStmt] F3(...)
-# 206| 0: [LocalFunction] F3
+# 202| 0: [Parameter] p
+# 202| -1: [TypeMention] int
+# 203| 4: [BlockStmt] {...}
+# 204| 0: [LocalFunctionStmt] F3(...)
+# 204| 0: [LocalFunction] F3
#-----| 2: (Parameters)
-# 206| 0: [Parameter] q
-# 206| -1: [TypeMention] int
-# 206| 4: [BlockStmt] {...}
-# 206| 0: [ReturnStmt] return ...;
-# 206| 0: [RefExpr] ref ...
-# 206| 0: [ParameterAccess] access to parameter q
-# 207| 1: [ReturnStmt] return ...;
-# 207| 0: [RefExpr] ref ...
-# 207| 0: [ParameterAccess] access to parameter p
-# 210| 7: [DelegateType] RefFn
+# 204| 0: [Parameter] q
+# 204| -1: [TypeMention] int
+# 204| 4: [BlockStmt] {...}
+# 204| 0: [ReturnStmt] return ...;
+# 204| 0: [RefExpr] ref ...
+# 204| 0: [ParameterAccess] access to parameter q
+# 205| 1: [ReturnStmt] return ...;
+# 205| 0: [RefExpr] ref ...
+# 205| 0: [ParameterAccess] access to parameter p
+# 208| 7: [DelegateType] RefFn
#-----| 2: (Parameters)
-# 210| 0: [Parameter] p
-# 210| -1: [TypeMention] int
-# 213| [Class] Discards
-# 215| 5: [Method] f
-# 215| -1: [TypeMention] (int, double)
-# 215| 1: [TypeMention] int
-# 215| 2: [TypeMention] double
+# 208| 0: [Parameter] p
+# 208| -1: [TypeMention] int
+# 211| [Class] Discards
+# 213| 5: [Method] f
+# 213| -1: [TypeMention] (int, double)
+# 213| 1: [TypeMention] int
+# 213| 2: [TypeMention] double
#-----| 2: (Parameters)
-# 215| 0: [Parameter] x
-# 215| -1: [TypeMention] bool
-# 216| 4: [BlockStmt] {...}
-# 217| 0: [ExprStmt] ...;
-# 217| 0: [AssignExpr] ... = ...
-# 217| 0: [ParameterAccess] access to parameter x
-# 217| 1: [BoolLiteral] false
-# 218| 1: [ReturnStmt] return ...;
-# 218| 0: [TupleExpr] (..., ...)
-# 218| 0: [IntLiteral] 0
-# 218| 1: [DoubleLiteral] 0
-# 221| 6: [Method] Test
-# 221| -1: [TypeMention] Void
-# 222| 4: [BlockStmt] {...}
-# 223| 0: [ExprStmt] ...;
+# 213| 0: [Parameter] x
+# 213| -1: [TypeMention] bool
+# 214| 4: [BlockStmt] {...}
+# 215| 0: [ExprStmt] ...;
+# 215| 0: [AssignExpr] ... = ...
+# 215| 0: [ParameterAccess] access to parameter x
+# 215| 1: [BoolLiteral] false
+# 216| 1: [ReturnStmt] return ...;
+# 216| 0: [TupleExpr] (..., ...)
+# 216| 0: [IntLiteral] 0
+# 216| 1: [DoubleLiteral] 0
+# 219| 6: [Method] Test
+# 219| -1: [TypeMention] Void
+# 220| 4: [BlockStmt] {...}
+# 221| 0: [ExprStmt] ...;
+# 221| 0: [AssignExpr] ... = ...
+# 221| 0: [DiscardExpr] _
+# 221| 1: [MethodCall] call to method f
+# 221| 0: [DiscardExpr] _
+# 222| 1: [ExprStmt] ...;
+# 222| 0: [AssignExpr] ... = ...
+# 222| 0: [TupleExpr] (..., ...)
+# 222| 0: [DiscardExpr] _
+# 222| 1: [DiscardExpr] _
+# 222| 1: [MethodCall] call to method f
+# 222| 0: [DiscardExpr] _
+# 223| 2: [ExprStmt] ...;
# 223| 0: [AssignExpr] ... = ...
-# 223| 0: [DiscardExpr] _
+# 223| 0: [TupleExpr] (..., ...)
+# 223| 0: [LocalVariableDeclExpr] Int32 x
+# 223| 1: [DiscardExpr] _
# 223| 1: [MethodCall] call to method f
# 223| 0: [DiscardExpr] _
-# 224| 1: [ExprStmt] ...;
+# 224| 3: [ExprStmt] ...;
# 224| 0: [AssignExpr] ... = ...
# 224| 0: [TupleExpr] (..., ...)
# 224| 0: [DiscardExpr] _
-# 224| 1: [DiscardExpr] _
+# 224| 1: [LocalVariableDeclExpr] Double y
# 224| 1: [MethodCall] call to method f
-# 224| 0: [DiscardExpr] _
-# 225| 2: [ExprStmt] ...;
-# 225| 0: [AssignExpr] ... = ...
-# 225| 0: [TupleExpr] (..., ...)
-# 225| 0: [LocalVariableDeclExpr] Int32 x
-# 225| 1: [DiscardExpr] _
-# 225| 1: [MethodCall] call to method f
-# 225| 0: [DiscardExpr] _
-# 226| 3: [ExprStmt] ...;
-# 226| 0: [AssignExpr] ... = ...
-# 226| 0: [TupleExpr] (..., ...)
-# 226| 0: [DiscardExpr] _
-# 226| 1: [LocalVariableDeclExpr] Double y
-# 226| 1: [MethodCall] call to method f
-# 226| 0: [LocalVariableAccess,LocalVariableDeclExpr] Boolean z
-# 230| [Class] Patterns
-# 232| 5: [Method] Test
-# 232| -1: [TypeMention] Void
-# 233| 4: [BlockStmt] {...}
-# 234| 0: [LocalVariableDeclStmt] ... ...;
-# 234| 0: [LocalVariableDeclAndInitExpr] Object o = ...
-# 234| -1: [TypeMention] object
-# 234| 0: [LocalVariableAccess] access to local variable o
-# 234| 1: [NullLiteral] null
-# 235| 1: [IfStmt] if (...) ...
-# 235| 0: [LogicalAndExpr] ... && ...
-# 235| 0: [IsExpr] ... is ...
-# 235| 0: [LocalVariableAccess] access to local variable o
-# 235| 1: [VariablePatternExpr] Int32 i1
-# 235| 0: [TypeMention] int
-# 235| 1: [GTExpr] ... > ...
-# 235| 0: [LocalVariableAccess] access to local variable i1
-# 235| 1: [IntLiteral] 0
-# 236| 1: [BlockStmt] {...}
-# 237| 0: [ExprStmt] ...;
-# 237| 0: [MethodCall] call to method WriteLine
-# 237| -1: [TypeAccess] access to type Console
-# 237| 0: [TypeMention] Console
-# 237| 0: [InterpolatedStringExpr] $"..."
-# 237| 0: [StringLiteral] "int "
-# 237| 1: [LocalVariableAccess] access to local variable i1
-# 239| 2: [IfStmt] if (...) ...
-# 239| 0: [IsExpr] ... is ...
-# 239| 0: [LocalVariableAccess] access to local variable o
-# 239| 1: [VariablePatternExpr] String s1
-# 239| 0: [TypeMention] string
-# 240| 1: [BlockStmt] {...}
-# 241| 0: [ExprStmt] ...;
-# 241| 0: [MethodCall] call to method WriteLine
-# 241| -1: [TypeAccess] access to type Console
-# 241| 0: [TypeMention] Console
-# 241| 0: [InterpolatedStringExpr] $"..."
-# 241| 0: [StringLiteral] "string "
-# 241| 1: [LocalVariableAccess] access to local variable s1
-# 243| 2: [IfStmt] if (...) ...
-# 243| 0: [IsExpr] ... is ...
-# 243| 0: [LocalVariableAccess] access to local variable o
-# 243| 1: [TypeAccessPatternExpr] access to type Double
-# 243| 0: [TypeMention] double
-# 244| 1: [BlockStmt] {...}
-# 246| 2: [IfStmt] if (...) ...
-# 246| 0: [IsExpr] ... is ...
-# 246| 0: [LocalVariableAccess] access to local variable o
-# 246| 1: [VariablePatternExpr] Object v1
-# 247| 1: [BlockStmt] {...}
-# 250| 2: [SwitchStmt] switch (...) {...}
-# 250| 0: [LocalVariableAccess] access to local variable o
-# 252| 0: [ConstCase] case ...:
-# 252| 0: [ConstantPatternExpr,StringLiteral] "xyz"
-# 253| 1: [BreakStmt] break;
-# 254| 2: [ConstCase] case ...:
-# 254| 0: [ConstantPatternExpr,StringLiteral] ""
-# 254| 1: [LTExpr] ... < ...
-# 254| 0: [IntLiteral] 1
-# 254| 1: [IntLiteral] 2
-# 255| 3: [BreakStmt] break;
-# 256| 4: [ConstCase] case ...:
-# 256| 0: [ConstantPatternExpr,StringLiteral] "x"
-# 256| 1: [IsExpr] ... is ...
-# 256| 0: [LocalVariableAccess] access to local variable o
-# 256| 1: [VariablePatternExpr] String s4
-# 256| 0: [TypeMention] string
-# 257| 5: [ExprStmt] ...;
-# 257| 0: [MethodCall] call to method WriteLine
-# 257| -1: [TypeAccess] access to type Console
-# 257| 0: [TypeMention] Console
-# 257| 0: [InterpolatedStringExpr] $"..."
-# 257| 0: [StringLiteral] "x "
-# 257| 1: [LocalVariableAccess] access to local variable s4
-# 258| 6: [BreakStmt] break;
-# 259| 7: [CaseStmt] case ...:
-# 259| 0: [VariablePatternExpr] Int32 i2
-# 259| 0: [TypeMention] int
-# 259| 1: [GTExpr] ... > ...
-# 259| 0: [LocalVariableAccess] access to local variable i2
-# 259| 1: [IntLiteral] 0
-# 260| 8: [ExprStmt] ...;
-# 260| 0: [MethodCall] call to method WriteLine
-# 260| -1: [TypeAccess] access to type Console
-# 260| 0: [TypeMention] Console
-# 260| 0: [InterpolatedStringExpr] $"..."
-# 260| 0: [StringLiteral] "positive "
-# 260| 1: [LocalVariableAccess] access to local variable i2
-# 261| 9: [BreakStmt] break;
-# 262| 10: [CaseStmt] case ...:
-# 262| 0: [VariablePatternExpr] Int32 i3
-# 262| 0: [TypeMention] int
-# 263| 11: [ExprStmt] ...;
-# 263| 0: [MethodCall] call to method WriteLine
-# 263| -1: [TypeAccess] access to type Console
-# 263| 0: [TypeMention] Console
-# 263| 0: [InterpolatedStringExpr] $"..."
-# 263| 0: [StringLiteral] "int "
-# 263| 1: [LocalVariableAccess] access to local variable i3
-# 264| 12: [BreakStmt] break;
-# 265| 13: [CaseStmt] case ...:
-# 265| 0: [VariablePatternExpr] String s2
-# 265| 0: [TypeMention] string
-# 266| 14: [ExprStmt] ...;
-# 266| 0: [MethodCall] call to method WriteLine
-# 266| -1: [TypeAccess] access to type Console
-# 266| 0: [TypeMention] Console
-# 266| 0: [InterpolatedStringExpr] $"..."
-# 266| 0: [StringLiteral] "string "
-# 266| 1: [LocalVariableAccess] access to local variable s2
-# 267| 15: [BreakStmt] break;
-# 268| 16: [CaseStmt] case ...:
-# 268| 0: [TypeAccessPatternExpr] access to type Double
-# 268| 0: [TypeMention] double
-# 269| 17: [ExprStmt] ...;
-# 269| 0: [MethodCall] call to method WriteLine
-# 269| -1: [TypeAccess] access to type Console
-# 269| 0: [TypeMention] Console
-# 269| 0: [StringLiteral] "Double"
-# 270| 18: [BreakStmt] break;
-# 271| 19: [CaseStmt] case ...:
-# 271| 0: [VariablePatternExpr] Object v2
-# 272| 20: [BreakStmt] break;
-# 273| 21: [DefaultCase] default:
-# 274| 22: [ExprStmt] ...;
-# 274| 0: [MethodCall] call to method WriteLine
-# 274| -1: [TypeAccess] access to type Console
-# 274| 0: [TypeMention] Console
-# 274| 0: [StringLiteral] "Something else"
-# 275| 23: [BreakStmt] break;
-# 280| [Class] ForeachStatements
-# 282| 5: [Method] Test
-# 282| -1: [TypeMention] Void
-# 283| 4: [BlockStmt] {...}
-# 284| 0: [LocalVariableDeclStmt] ... ...;
-# 284| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ...
-# 284| -1: [TypeMention] Dictionary
-# 284| 0: [LocalVariableAccess] access to local variable dict
-# 284| 1: [ObjectCreation] object creation of type Dictionary
-# 284| 0: [TypeMention] Dictionary
-# 284| 1: [TypeMention] int
-# 284| 2: [TypeMention] string
-# 285| 1: [LocalVariableDeclStmt] ... ...;
-# 285| 0: [LocalVariableDeclAndInitExpr] IEnumerable<(Int32,String)> list = ...
-# 285| -1: [TypeMention] IEnumerable<(Int32,String)>
-# 285| 0: [LocalVariableAccess] access to local variable list
-# 285| 1: [MethodCall] call to method Select
-# 285| -1: [LocalVariableAccess] access to local variable dict
-# 285| 0: [LambdaExpr] (...) => ...
+# 224| 0: [LocalVariableAccess,LocalVariableDeclExpr] Boolean z
+# 228| [Class] Patterns
+# 230| 5: [Method] Test
+# 230| -1: [TypeMention] Void
+# 231| 4: [BlockStmt] {...}
+# 232| 0: [LocalVariableDeclStmt] ... ...;
+# 232| 0: [LocalVariableDeclAndInitExpr] Object o = ...
+# 232| -1: [TypeMention] object
+# 232| 0: [LocalVariableAccess] access to local variable o
+# 232| 1: [NullLiteral] null
+# 233| 1: [IfStmt] if (...) ...
+# 233| 0: [LogicalAndExpr] ... && ...
+# 233| 0: [IsExpr] ... is ...
+# 233| 0: [LocalVariableAccess] access to local variable o
+# 233| 1: [VariablePatternExpr] Int32 i1
+# 233| 0: [TypeMention] int
+# 233| 1: [GTExpr] ... > ...
+# 233| 0: [LocalVariableAccess] access to local variable i1
+# 233| 1: [IntLiteral] 0
+# 234| 1: [BlockStmt] {...}
+# 235| 0: [ExprStmt] ...;
+# 235| 0: [MethodCall] call to method WriteLine
+# 235| -1: [TypeAccess] access to type Console
+# 235| 0: [TypeMention] Console
+# 235| 0: [InterpolatedStringExpr] $"..."
+# 235| 0: [StringLiteral] "int "
+# 235| 1: [LocalVariableAccess] access to local variable i1
+# 237| 2: [IfStmt] if (...) ...
+# 237| 0: [IsExpr] ... is ...
+# 237| 0: [LocalVariableAccess] access to local variable o
+# 237| 1: [VariablePatternExpr] String s1
+# 237| 0: [TypeMention] string
+# 238| 1: [BlockStmt] {...}
+# 239| 0: [ExprStmt] ...;
+# 239| 0: [MethodCall] call to method WriteLine
+# 239| -1: [TypeAccess] access to type Console
+# 239| 0: [TypeMention] Console
+# 239| 0: [InterpolatedStringExpr] $"..."
+# 239| 0: [StringLiteral] "string "
+# 239| 1: [LocalVariableAccess] access to local variable s1
+# 241| 2: [IfStmt] if (...) ...
+# 241| 0: [IsExpr] ... is ...
+# 241| 0: [LocalVariableAccess] access to local variable o
+# 241| 1: [TypeAccessPatternExpr] access to type Double
+# 241| 0: [TypeMention] double
+# 242| 1: [BlockStmt] {...}
+# 244| 2: [IfStmt] if (...) ...
+# 244| 0: [IsExpr] ... is ...
+# 244| 0: [LocalVariableAccess] access to local variable o
+# 244| 1: [VariablePatternExpr] Object v1
+# 245| 1: [BlockStmt] {...}
+# 248| 2: [SwitchStmt] switch (...) {...}
+# 248| 0: [LocalVariableAccess] access to local variable o
+# 250| 0: [ConstCase] case ...:
+# 250| 0: [ConstantPatternExpr,StringLiteral] "xyz"
+# 251| 1: [BreakStmt] break;
+# 252| 2: [ConstCase] case ...:
+# 252| 0: [ConstantPatternExpr,StringLiteral] ""
+# 252| 1: [LTExpr] ... < ...
+# 252| 0: [IntLiteral] 1
+# 252| 1: [IntLiteral] 2
+# 253| 3: [BreakStmt] break;
+# 254| 4: [ConstCase] case ...:
+# 254| 0: [ConstantPatternExpr,StringLiteral] "x"
+# 254| 1: [IsExpr] ... is ...
+# 254| 0: [LocalVariableAccess] access to local variable o
+# 254| 1: [VariablePatternExpr] String s4
+# 254| 0: [TypeMention] string
+# 255| 5: [ExprStmt] ...;
+# 255| 0: [MethodCall] call to method WriteLine
+# 255| -1: [TypeAccess] access to type Console
+# 255| 0: [TypeMention] Console
+# 255| 0: [InterpolatedStringExpr] $"..."
+# 255| 0: [StringLiteral] "x "
+# 255| 1: [LocalVariableAccess] access to local variable s4
+# 256| 6: [BreakStmt] break;
+# 257| 7: [CaseStmt] case ...:
+# 257| 0: [VariablePatternExpr] Int32 i2
+# 257| 0: [TypeMention] int
+# 257| 1: [GTExpr] ... > ...
+# 257| 0: [LocalVariableAccess] access to local variable i2
+# 257| 1: [IntLiteral] 0
+# 258| 8: [ExprStmt] ...;
+# 258| 0: [MethodCall] call to method WriteLine
+# 258| -1: [TypeAccess] access to type Console
+# 258| 0: [TypeMention] Console
+# 258| 0: [InterpolatedStringExpr] $"..."
+# 258| 0: [StringLiteral] "positive "
+# 258| 1: [LocalVariableAccess] access to local variable i2
+# 259| 9: [BreakStmt] break;
+# 260| 10: [CaseStmt] case ...:
+# 260| 0: [VariablePatternExpr] Int32 i3
+# 260| 0: [TypeMention] int
+# 261| 11: [ExprStmt] ...;
+# 261| 0: [MethodCall] call to method WriteLine
+# 261| -1: [TypeAccess] access to type Console
+# 261| 0: [TypeMention] Console
+# 261| 0: [InterpolatedStringExpr] $"..."
+# 261| 0: [StringLiteral] "int "
+# 261| 1: [LocalVariableAccess] access to local variable i3
+# 262| 12: [BreakStmt] break;
+# 263| 13: [CaseStmt] case ...:
+# 263| 0: [VariablePatternExpr] String s2
+# 263| 0: [TypeMention] string
+# 264| 14: [ExprStmt] ...;
+# 264| 0: [MethodCall] call to method WriteLine
+# 264| -1: [TypeAccess] access to type Console
+# 264| 0: [TypeMention] Console
+# 264| 0: [InterpolatedStringExpr] $"..."
+# 264| 0: [StringLiteral] "string "
+# 264| 1: [LocalVariableAccess] access to local variable s2
+# 265| 15: [BreakStmt] break;
+# 266| 16: [CaseStmt] case ...:
+# 266| 0: [TypeAccessPatternExpr] access to type Double
+# 266| 0: [TypeMention] double
+# 267| 17: [ExprStmt] ...;
+# 267| 0: [MethodCall] call to method WriteLine
+# 267| -1: [TypeAccess] access to type Console
+# 267| 0: [TypeMention] Console
+# 267| 0: [StringLiteral] "Double"
+# 268| 18: [BreakStmt] break;
+# 269| 19: [CaseStmt] case ...:
+# 269| 0: [VariablePatternExpr] Object v2
+# 270| 20: [BreakStmt] break;
+# 271| 21: [DefaultCase] default:
+# 272| 22: [ExprStmt] ...;
+# 272| 0: [MethodCall] call to method WriteLine
+# 272| -1: [TypeAccess] access to type Console
+# 272| 0: [TypeMention] Console
+# 272| 0: [StringLiteral] "Something else"
+# 273| 23: [BreakStmt] break;
+# 278| [Class] ForeachStatements
+# 280| 5: [Method] Test
+# 280| -1: [TypeMention] Void
+# 281| 4: [BlockStmt] {...}
+# 282| 0: [LocalVariableDeclStmt] ... ...;
+# 282| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ...
+# 282| -1: [TypeMention] Dictionary
+# 282| 0: [LocalVariableAccess] access to local variable dict
+# 282| 1: [ObjectCreation] object creation of type Dictionary
+# 282| 0: [TypeMention] Dictionary
+# 282| 1: [TypeMention] int
+# 282| 2: [TypeMention] string
+# 283| 1: [LocalVariableDeclStmt] ... ...;
+# 283| 0: [LocalVariableDeclAndInitExpr] IEnumerable<(Int32,String)> list = ...
+# 283| -1: [TypeMention] IEnumerable<(Int32,String)>
+# 283| 0: [LocalVariableAccess] access to local variable list
+# 283| 1: [MethodCall] call to method Select
+# 283| -1: [LocalVariableAccess] access to local variable dict
+# 283| 0: [LambdaExpr] (...) => ...
#-----| 2: (Parameters)
-# 285| 0: [Parameter] item
-# 285| 4: [TupleExpr] (..., ...)
-# 285| 0: [PropertyCall] access to property Key
-# 285| -1: [ParameterAccess] access to parameter item
-# 285| 1: [PropertyCall] access to property Value
-# 285| -1: [ParameterAccess] access to parameter item
-# 287| 2: [ForeachStmt] foreach (... ... in ...) ...
+# 283| 0: [Parameter] item
+# 283| 4: [TupleExpr] (..., ...)
+# 283| 0: [PropertyCall] access to property Key
+# 283| -1: [ParameterAccess] access to parameter item
+# 283| 1: [PropertyCall] access to property Value
+# 283| -1: [ParameterAccess] access to parameter item
+# 285| 2: [ForeachStmt] foreach (... ... in ...) ...
+# 285| 0: [TupleExpr] (..., ...)
+# 285| 0: [LocalVariableDeclExpr] Int32 a
+# 285| 1: [LocalVariableDeclExpr] String b
+# 285| 1: [LocalVariableAccess] access to local variable list
+# 285| 2: [BlockStmt] {...}
+# 287| 3: [ForeachStmt] foreach (... ... in ...) ...
# 287| 0: [TupleExpr] (..., ...)
# 287| 0: [LocalVariableDeclExpr] Int32 a
# 287| 1: [LocalVariableDeclExpr] String b
# 287| 1: [LocalVariableAccess] access to local variable list
# 287| 2: [BlockStmt] {...}
-# 289| 3: [ForeachStmt] foreach (... ... in ...) ...
+# 289| 4: [ForeachStmt] foreach (... ... in ...) ...
# 289| 0: [TupleExpr] (..., ...)
# 289| 0: [LocalVariableDeclExpr] Int32 a
# 289| 1: [LocalVariableDeclExpr] String b
# 289| 1: [LocalVariableAccess] access to local variable list
# 289| 2: [BlockStmt] {...}
-# 291| 4: [ForeachStmt] foreach (... ... in ...) ...
-# 291| 0: [TupleExpr] (..., ...)
-# 291| 0: [LocalVariableDeclExpr] Int32 a
-# 291| 1: [LocalVariableDeclExpr] String b
-# 291| 1: [LocalVariableAccess] access to local variable list
-# 291| 2: [BlockStmt] {...}
-# 295| [Class] ForLoops
-# 297| 5: [Method] Test
-# 297| -1: [TypeMention] Void
-# 298| 4: [BlockStmt] {...}
-# 299| 0: [ForStmt] for (...;...;...) ...
-# 299| -1: [LocalVariableDeclAndInitExpr] Int32 x = ...
-# 299| -1: [TypeMention] int
-# 299| 0: [LocalVariableAccess] access to local variable x
-# 299| 1: [IntLiteral] 0
-# 299| 0: [LogicalAndExpr] ... && ...
-# 299| 0: [LTExpr] ... < ...
-# 299| 0: [LocalVariableAccess] access to local variable x
-# 299| 1: [IntLiteral] 10
-# 299| 1: [IsExpr] ... is ...
-# 299| 0: [LocalVariableAccess] access to local variable x
-# 299| 1: [VariablePatternExpr] Int32 y
-# 299| 0: [TypeMention] int
-# 299| 1: [PreIncrExpr] ++...
-# 299| 0: [LocalVariableAccess] access to local variable x
-# 300| 2: [BlockStmt] {...}
-# 301| 0: [ExprStmt] ...;
-# 301| 0: [MethodCall] call to method WriteLine
-# 301| -1: [TypeAccess] access to type Console
-# 301| 0: [TypeMention] Console
-# 301| 0: [LocalVariableAccess] access to local variable y
+# 293| [Class] ForLoops
+# 295| 5: [Method] Test
+# 295| -1: [TypeMention] Void
+# 296| 4: [BlockStmt] {...}
+# 297| 0: [ForStmt] for (...;...;...) ...
+# 297| -1: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 297| -1: [TypeMention] int
+# 297| 0: [LocalVariableAccess] access to local variable x
+# 297| 1: [IntLiteral] 0
+# 297| 0: [LogicalAndExpr] ... && ...
+# 297| 0: [LTExpr] ... < ...
+# 297| 0: [LocalVariableAccess] access to local variable x
+# 297| 1: [IntLiteral] 10
+# 297| 1: [IsExpr] ... is ...
+# 297| 0: [LocalVariableAccess] access to local variable x
+# 297| 1: [VariablePatternExpr] Int32 y
+# 297| 0: [TypeMention] int
+# 297| 1: [PreIncrExpr] ++...
+# 297| 0: [LocalVariableAccess] access to local variable x
+# 298| 2: [BlockStmt] {...}
+# 299| 0: [ExprStmt] ...;
+# 299| 0: [MethodCall] call to method WriteLine
+# 299| -1: [TypeAccess] access to type Console
+# 299| 0: [TypeMention] Console
+# 299| 0: [LocalVariableAccess] access to local variable y
diff --git a/csharp/ql/test/library-tests/csharp7/RefDelegates.expected b/csharp/ql/test/library-tests/csharp7/RefDelegates.expected
index b26c77efc50..55136e4e180 100644
--- a/csharp/ql/test/library-tests/csharp7/RefDelegates.expected
+++ b/csharp/ql/test/library-tests/csharp7/RefDelegates.expected
@@ -1 +1 @@
-| CSharp7.cs:210:22:210:26 | RefFn |
+| CSharp7.cs:208:22:208:26 | RefFn |
diff --git a/csharp/ql/test/library-tests/csharp7/RefExprs.expected b/csharp/ql/test/library-tests/csharp7/RefExprs.expected
index bb1a22d1e19..e5239741940 100644
--- a/csharp/ql/test/library-tests/csharp7/RefExprs.expected
+++ b/csharp/ql/test/library-tests/csharp7/RefExprs.expected
@@ -1,6 +1,6 @@
-| CSharp7.cs:193:22:193:27 | ref ... | CSharp7.cs:193:26:193:27 | access to local variable v1 | Int32 |
-| CSharp7.cs:197:22:197:33 | ref ... | CSharp7.cs:197:26:197:33 | access to array element | Int32 |
-| CSharp7.cs:198:22:198:27 | ref ... | CSharp7.cs:198:26:198:27 | access to local variable r1 | Int32 |
-| CSharp7.cs:200:22:200:35 | ref ... | CSharp7.cs:200:26:200:35 | call to method F2 | Int32 |
-| CSharp7.cs:206:40:206:44 | ref ... | CSharp7.cs:206:44:206:44 | access to parameter q | Int32 |
-| CSharp7.cs:207:16:207:20 | ref ... | CSharp7.cs:207:20:207:20 | access to parameter p | Int32 |
+| CSharp7.cs:191:22:191:27 | ref ... | CSharp7.cs:191:26:191:27 | access to local variable v1 | Int32 |
+| CSharp7.cs:195:22:195:33 | ref ... | CSharp7.cs:195:26:195:33 | access to array element | Int32 |
+| CSharp7.cs:196:22:196:27 | ref ... | CSharp7.cs:196:26:196:27 | access to local variable r1 | Int32 |
+| CSharp7.cs:198:22:198:35 | ref ... | CSharp7.cs:198:26:198:35 | call to method F2 | Int32 |
+| CSharp7.cs:204:40:204:44 | ref ... | CSharp7.cs:204:44:204:44 | access to parameter q | Int32 |
+| CSharp7.cs:205:16:205:20 | ref ... | CSharp7.cs:205:20:205:20 | access to parameter p | Int32 |
diff --git a/csharp/ql/test/library-tests/csharp7/RefFunctions.expected b/csharp/ql/test/library-tests/csharp7/RefFunctions.expected
index c2899f5443f..004f8119f49 100644
--- a/csharp/ql/test/library-tests/csharp7/RefFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp7/RefFunctions.expected
@@ -1,2 +1,2 @@
-| CSharp7.cs:204:13:204:14 | F2 |
-| CSharp7.cs:206:9:206:47 | F3 |
+| CSharp7.cs:202:13:202:14 | F2 |
+| CSharp7.cs:204:9:204:47 | F3 |
diff --git a/csharp/ql/test/library-tests/csharp7/RefVariables.expected b/csharp/ql/test/library-tests/csharp7/RefVariables.expected
index ed8f2d59b45..c585241b15f 100644
--- a/csharp/ql/test/library-tests/csharp7/RefVariables.expected
+++ b/csharp/ql/test/library-tests/csharp7/RefVariables.expected
@@ -1,4 +1,4 @@
-| CSharp7.cs:193:17:193:18 | r1 |
-| CSharp7.cs:197:17:197:18 | r2 |
-| CSharp7.cs:198:17:198:18 | r3 |
-| CSharp7.cs:200:17:200:18 | r4 |
+| CSharp7.cs:191:17:191:18 | r1 |
+| CSharp7.cs:195:17:195:18 | r2 |
+| CSharp7.cs:196:17:196:18 | r3 |
+| CSharp7.cs:198:17:198:18 | r4 |
diff --git a/csharp/ql/test/library-tests/csharp7/TaintReaches.expected b/csharp/ql/test/library-tests/csharp7/TaintReaches.expected
index e207c684050..6e9a4c8dcfa 100644
--- a/csharp/ql/test/library-tests/csharp7/TaintReaches.expected
+++ b/csharp/ql/test/library-tests/csharp7/TaintReaches.expected
@@ -1,15 +1,15 @@
-| CSharp7.cs:41:13:41:21 | "tainted" | CSharp7.cs:41:9:41:21 | SSA def(x) |
-| CSharp7.cs:109:29:109:37 | "DefUse1" | CSharp7.cs:109:9:109:46 | SSA def(m1) |
-| CSharp7.cs:109:29:109:37 | "DefUse1" | CSharp7.cs:112:27:112:28 | access to local variable m1 |
-| CSharp7.cs:123:28:123:36 | "DefUse3" | CSharp7.cs:123:22:123:36 | ... = ... |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:177:16:177:30 | SSA def(src) |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:182:23:182:25 | access to local variable src |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:183:23:183:25 | access to local variable src |
-| CSharp7.cs:177:22:177:30 | "tainted" | CSharp7.cs:184:23:184:25 | access to local variable src |
-| CSharp7.cs:178:38:178:39 | "" | CSharp7.cs:178:31:178:39 | ... + ... |
-| CSharp7.cs:237:33:237:36 | "int " | CSharp7.cs:237:31:237:41 | $"..." |
-| CSharp7.cs:241:33:241:39 | "string " | CSharp7.cs:241:31:241:44 | $"..." |
-| CSharp7.cs:257:37:257:38 | "x " | CSharp7.cs:257:35:257:43 | $"..." |
-| CSharp7.cs:260:37:260:45 | "positive " | CSharp7.cs:260:35:260:50 | $"..." |
-| CSharp7.cs:263:37:263:40 | "int " | CSharp7.cs:263:35:263:45 | $"..." |
-| CSharp7.cs:266:37:266:43 | "string " | CSharp7.cs:266:35:266:48 | $"..." |
+| CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:21 | SSA def(x) |
+| CSharp7.cs:107:29:107:37 | "DefUse1" | CSharp7.cs:107:9:107:46 | SSA def(m1) |
+| CSharp7.cs:107:29:107:37 | "DefUse1" | CSharp7.cs:110:27:110:28 | access to local variable m1 |
+| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:36 | ... = ... |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:16:175:30 | SSA def(src) |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:180:23:180:25 | access to local variable src |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:181:23:181:25 | access to local variable src |
+| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:182:23:182:25 | access to local variable src |
+| CSharp7.cs:176:38:176:39 | "" | CSharp7.cs:176:31:176:39 | ... + ... |
+| CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." |
+| CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." |
+| CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:35:255:43 | $"..." |
+| CSharp7.cs:258:37:258:45 | "positive " | CSharp7.cs:258:35:258:50 | $"..." |
+| CSharp7.cs:261:37:261:40 | "int " | CSharp7.cs:261:35:261:45 | $"..." |
+| CSharp7.cs:264:37:264:43 | "string " | CSharp7.cs:264:35:264:48 | $"..." |
diff --git a/csharp/ql/test/library-tests/csharp7/Throw.expected b/csharp/ql/test/library-tests/csharp7/Throw.expected
index 9e76364cc24..3108969f710 100644
--- a/csharp/ql/test/library-tests/csharp7/Throw.expected
+++ b/csharp/ql/test/library-tests/csharp7/Throw.expected
@@ -1 +1 @@
-| CSharp7.cs:33:28:33:59 | throw ... | CSharp7.cs:33:34:33:59 | object creation of type ArgumentException |
+| CSharp7.cs:31:28:31:59 | throw ... | CSharp7.cs:31:34:31:59 | object creation of type ArgumentException |
diff --git a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected
index 9ffbb3b53f4..63042007ef6 100644
--- a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected
+++ b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected
@@ -1,45 +1,45 @@
-| CSharp7.cs:66:16:66:27 | (..., ...) | construct |
-| CSharp7.cs:71:9:71:22 | (..., ...) | deconstruct |
-| CSharp7.cs:73:9:73:14 | (..., ...) | deconstruct |
-| CSharp7.cs:75:9:75:23 | (..., ...) | deconstruct |
-| CSharp7.cs:75:27:75:35 | (..., ...) | construct |
-| CSharp7.cs:76:9:76:14 | (..., ...) | deconstruct |
-| CSharp7.cs:76:18:76:23 | (..., ...) | deconstruct |
+| CSharp7.cs:64:16:64:27 | (..., ...) | construct |
+| CSharp7.cs:69:9:69:22 | (..., ...) | deconstruct |
+| CSharp7.cs:71:9:71:14 | (..., ...) | deconstruct |
+| CSharp7.cs:73:9:73:23 | (..., ...) | deconstruct |
+| CSharp7.cs:73:27:73:35 | (..., ...) | construct |
+| CSharp7.cs:74:9:74:14 | (..., ...) | deconstruct |
+| CSharp7.cs:74:18:74:23 | (..., ...) | deconstruct |
+| CSharp7.cs:74:27:74:32 | (..., ...) | construct |
+| CSharp7.cs:75:9:75:31 | (..., ...) | deconstruct |
+| CSharp7.cs:75:17:75:30 | (..., ...) | deconstruct |
+| CSharp7.cs:75:35:75:40 | (..., ...) | construct |
+| CSharp7.cs:76:9:76:19 | (..., ...) | deconstruct |
+| CSharp7.cs:76:13:76:18 | (..., ...) | deconstruct |
+| CSharp7.cs:76:23:76:33 | (..., ...) | construct |
| CSharp7.cs:76:27:76:32 | (..., ...) | construct |
-| CSharp7.cs:77:9:77:31 | (..., ...) | deconstruct |
-| CSharp7.cs:77:17:77:30 | (..., ...) | deconstruct |
-| CSharp7.cs:77:35:77:40 | (..., ...) | construct |
-| CSharp7.cs:78:9:78:19 | (..., ...) | deconstruct |
-| CSharp7.cs:78:13:78:18 | (..., ...) | deconstruct |
-| CSharp7.cs:78:23:78:33 | (..., ...) | construct |
-| CSharp7.cs:78:27:78:32 | (..., ...) | construct |
-| CSharp7.cs:79:9:79:18 | (..., ...) | deconstruct |
-| CSharp7.cs:79:22:79:28 | (..., ...) | construct |
-| CSharp7.cs:84:16:84:24 | (..., ...) | construct |
-| CSharp7.cs:89:18:89:34 | (..., ...) | construct |
-| CSharp7.cs:90:9:90:24 | (..., ...) | deconstruct |
-| CSharp7.cs:97:18:97:38 | (..., ...) | construct |
-| CSharp7.cs:98:18:98:43 | (..., ...) | construct |
-| CSharp7.cs:98:22:98:42 | (..., ...) | construct |
-| CSharp7.cs:103:18:103:42 | (..., ...) | construct |
-| CSharp7.cs:104:18:104:47 | (..., ...) | construct |
-| CSharp7.cs:104:22:104:46 | (..., ...) | construct |
-| CSharp7.cs:109:9:109:24 | (..., ...) | deconstruct |
-| CSharp7.cs:109:28:109:46 | (..., ...) | construct |
-| CSharp7.cs:109:40:109:45 | (..., ...) | construct |
-| CSharp7.cs:112:9:112:22 | (..., ...) | deconstruct |
-| CSharp7.cs:112:14:112:21 | (..., ...) | deconstruct |
-| CSharp7.cs:112:26:112:33 | (..., ...) | construct |
-| CSharp7.cs:114:9:114:34 | (..., ...) | deconstruct |
-| CSharp7.cs:114:18:114:33 | (..., ...) | deconstruct |
-| CSharp7.cs:114:38:114:45 | (..., ...) | deconstruct |
-| CSharp7.cs:114:49:114:67 | (..., ...) | construct |
-| CSharp7.cs:114:61:114:66 | (..., ...) | construct |
-| CSharp7.cs:218:16:218:23 | (..., ...) | construct |
-| CSharp7.cs:224:9:224:14 | (..., ...) | deconstruct |
-| CSharp7.cs:225:9:225:18 | (..., ...) | deconstruct |
-| CSharp7.cs:226:9:226:18 | (..., ...) | deconstruct |
-| CSharp7.cs:285:40:285:61 | (..., ...) | construct |
-| CSharp7.cs:287:18:287:34 | (..., ...) | deconstruct |
-| CSharp7.cs:289:18:289:31 | (..., ...) | deconstruct |
-| CSharp7.cs:291:18:291:27 | (..., ...) | deconstruct |
+| CSharp7.cs:77:9:77:18 | (..., ...) | deconstruct |
+| CSharp7.cs:77:22:77:28 | (..., ...) | construct |
+| CSharp7.cs:82:16:82:24 | (..., ...) | construct |
+| CSharp7.cs:87:18:87:34 | (..., ...) | construct |
+| CSharp7.cs:88:9:88:24 | (..., ...) | deconstruct |
+| CSharp7.cs:95:18:95:38 | (..., ...) | construct |
+| CSharp7.cs:96:18:96:43 | (..., ...) | construct |
+| CSharp7.cs:96:22:96:42 | (..., ...) | construct |
+| CSharp7.cs:101:18:101:42 | (..., ...) | construct |
+| CSharp7.cs:102:18:102:47 | (..., ...) | construct |
+| CSharp7.cs:102:22:102:46 | (..., ...) | construct |
+| CSharp7.cs:107:9:107:24 | (..., ...) | deconstruct |
+| CSharp7.cs:107:28:107:46 | (..., ...) | construct |
+| CSharp7.cs:107:40:107:45 | (..., ...) | construct |
+| CSharp7.cs:110:9:110:22 | (..., ...) | deconstruct |
+| CSharp7.cs:110:14:110:21 | (..., ...) | deconstruct |
+| CSharp7.cs:110:26:110:33 | (..., ...) | construct |
+| CSharp7.cs:112:9:112:34 | (..., ...) | deconstruct |
+| CSharp7.cs:112:18:112:33 | (..., ...) | deconstruct |
+| CSharp7.cs:112:38:112:45 | (..., ...) | deconstruct |
+| CSharp7.cs:112:49:112:67 | (..., ...) | construct |
+| CSharp7.cs:112:61:112:66 | (..., ...) | construct |
+| CSharp7.cs:216:16:216:23 | (..., ...) | construct |
+| CSharp7.cs:222:9:222:14 | (..., ...) | deconstruct |
+| CSharp7.cs:223:9:223:18 | (..., ...) | deconstruct |
+| CSharp7.cs:224:9:224:18 | (..., ...) | deconstruct |
+| CSharp7.cs:283:40:283:61 | (..., ...) | construct |
+| CSharp7.cs:285:18:285:34 | (..., ...) | deconstruct |
+| CSharp7.cs:287:18:287:31 | (..., ...) | deconstruct |
+| CSharp7.cs:289:18:289:27 | (..., ...) | deconstruct |
diff --git a/csharp/ql/test/library-tests/csharp7/TupleExpr.expected b/csharp/ql/test/library-tests/csharp7/TupleExpr.expected
index ab16001b9a2..ed5c61051c1 100644
--- a/csharp/ql/test/library-tests/csharp7/TupleExpr.expected
+++ b/csharp/ql/test/library-tests/csharp7/TupleExpr.expected
@@ -1,92 +1,92 @@
-| CSharp7.cs:66:16:66:27 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:66:20:66:20 | 1 |
-| CSharp7.cs:66:16:66:27 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:66:26:66:26 | 2 |
-| CSharp7.cs:71:9:71:22 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:71:14:71:14 | Int32 x |
-| CSharp7.cs:71:9:71:22 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:71:21:71:21 | Int32 y |
-| CSharp7.cs:73:9:73:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:73:10:73:10 | access to local variable x |
-| CSharp7.cs:73:9:73:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:73:13:73:13 | access to local variable y |
-| CSharp7.cs:75:9:75:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 0 | CSharp7.cs:75:10:75:10 | access to local variable x |
-| CSharp7.cs:75:9:75:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 1 | CSharp7.cs:75:13:75:13 | access to local variable y |
-| CSharp7.cs:75:9:75:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 2 | CSharp7.cs:75:16:75:22 | access to field Item1 |
-| CSharp7.cs:75:27:75:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 0 | CSharp7.cs:75:28:75:28 | 1 |
-| CSharp7.cs:75:27:75:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 1 | CSharp7.cs:75:31:75:31 | 2 |
-| CSharp7.cs:75:27:75:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 2 | CSharp7.cs:75:34:75:34 | 3 |
-| CSharp7.cs:76:9:76:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:76:10:76:10 | access to local variable x |
-| CSharp7.cs:76:9:76:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:76:13:76:13 | access to local variable y |
-| CSharp7.cs:76:18:76:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:76:19:76:19 | access to local variable x |
-| CSharp7.cs:76:18:76:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:76:22:76:22 | access to local variable y |
-| CSharp7.cs:76:27:76:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:76:28:76:28 | 1 |
-| CSharp7.cs:76:27:76:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:76:31:76:31 | 2 |
-| CSharp7.cs:77:9:77:31 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:77:14:77:14 | Int32 a |
-| CSharp7.cs:77:9:77:31 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:77:17:77:30 | (..., ...) |
-| CSharp7.cs:77:17:77:30 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:77:22:77:22 | Int32 b |
-| CSharp7.cs:77:17:77:30 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:77:29:77:29 | Int32 c |
-| CSharp7.cs:77:35:77:40 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:77:36:77:36 | 1 |
-| CSharp7.cs:77:35:77:40 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:77:39:77:39 | access to local variable z |
-| CSharp7.cs:78:9:78:19 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:78:10:78:10 | access to local variable a |
-| CSharp7.cs:78:9:78:19 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:78:13:78:18 | (..., ...) |
-| CSharp7.cs:78:13:78:18 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:78:14:78:14 | access to local variable b |
-| CSharp7.cs:78:13:78:18 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:78:17:78:17 | access to local variable c |
-| CSharp7.cs:78:23:78:33 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:78:24:78:24 | access to local variable b |
-| CSharp7.cs:78:23:78:33 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:78:27:78:32 | (..., ...) |
-| CSharp7.cs:78:27:78:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:78:28:78:28 | access to local variable c |
-| CSharp7.cs:78:27:78:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:78:31:78:31 | access to local variable a |
-| CSharp7.cs:79:9:79:18 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:79:14:79:14 | String i |
-| CSharp7.cs:79:9:79:18 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:79:17:79:17 | Int32 j |
-| CSharp7.cs:79:22:79:28 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:79:23:79:24 | "" |
-| CSharp7.cs:79:22:79:28 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:79:27:79:27 | access to local variable x |
-| CSharp7.cs:84:16:84:24 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:84:20:84:20 | access to parameter x |
-| CSharp7.cs:84:16:84:24 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:84:23:84:23 | 2 |
-| CSharp7.cs:89:18:89:34 | (..., ...) | CSharp7.cs:89:18:89:34 | (String,String) | 0 | CSharp7.cs:89:19:89:27 | "tainted" |
-| CSharp7.cs:89:18:89:34 | (..., ...) | CSharp7.cs:89:18:89:34 | (String,String) | 1 | CSharp7.cs:89:30:89:33 | "X2" |
-| CSharp7.cs:90:9:90:24 | (..., ...) | CSharp7.cs:89:18:89:34 | (String,String) | 0 | CSharp7.cs:90:14:90:15 | String t2 |
-| CSharp7.cs:90:9:90:24 | (..., ...) | CSharp7.cs:89:18:89:34 | (String,String) | 1 | CSharp7.cs:90:22:90:23 | String t3 |
-| CSharp7.cs:97:18:97:38 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:97:19:97:19 | 1 |
-| CSharp7.cs:97:18:97:38 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:97:22:97:37 | "TupleExprNode1" |
-| CSharp7.cs:98:18:98:43 | (..., ...) | CSharp7.cs:98:18:98:43 | (Int32,(String,Int32)) | 0 | CSharp7.cs:98:19:98:19 | 1 |
-| CSharp7.cs:98:18:98:43 | (..., ...) | CSharp7.cs:98:18:98:43 | (Int32,(String,Int32)) | 1 | CSharp7.cs:98:22:98:42 | (..., ...) |
-| CSharp7.cs:98:22:98:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:98:23:98:38 | "TupleExprNode2" |
-| CSharp7.cs:98:22:98:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:98:41:98:41 | 2 |
-| CSharp7.cs:103:18:103:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:103:19:103:38 | "TupleMemberAccess1" |
-| CSharp7.cs:103:18:103:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:103:41:103:41 | 0 |
-| CSharp7.cs:104:18:104:47 | (..., ...) | CSharp7.cs:98:18:98:43 | (Int32,(String,Int32)) | 0 | CSharp7.cs:104:19:104:19 | 0 |
-| CSharp7.cs:104:18:104:47 | (..., ...) | CSharp7.cs:98:18:98:43 | (Int32,(String,Int32)) | 1 | CSharp7.cs:104:22:104:46 | (..., ...) |
-| CSharp7.cs:104:22:104:46 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:104:23:104:42 | "TupleMemberAccess2" |
-| CSharp7.cs:104:22:104:46 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:104:45:104:45 | 1 |
-| CSharp7.cs:109:9:109:24 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:109:14:109:15 | String m1 |
-| CSharp7.cs:109:9:109:24 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:109:22:109:23 | (Int32,Int32) m2 |
-| CSharp7.cs:109:28:109:46 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:109:29:109:37 | "DefUse1" |
-| CSharp7.cs:109:28:109:46 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:109:40:109:45 | (..., ...) |
-| CSharp7.cs:109:40:109:45 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:109:41:109:41 | 0 |
-| CSharp7.cs:109:40:109:45 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:109:44:109:44 | 1 |
-| CSharp7.cs:112:9:112:22 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:112:10:112:11 | access to local variable m3 |
-| CSharp7.cs:112:9:112:22 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:112:14:112:21 | (..., ...) |
-| CSharp7.cs:112:14:112:21 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:112:15:112:16 | access to local variable m4 |
-| CSharp7.cs:112:14:112:21 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:112:19:112:20 | access to local variable m5 |
-| CSharp7.cs:112:26:112:33 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:112:27:112:28 | access to local variable m1 |
-| CSharp7.cs:112:26:112:33 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:112:31:112:32 | access to local variable m2 |
-| CSharp7.cs:114:9:114:34 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:114:14:114:15 | String m7 |
-| CSharp7.cs:114:9:114:34 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:114:18:114:33 | (..., ...) |
-| CSharp7.cs:114:18:114:33 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:114:23:114:24 | Int32 m8 |
-| CSharp7.cs:114:18:114:33 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:114:31:114:32 | Int32 m9 |
-| CSharp7.cs:114:38:114:45 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:114:39:114:40 | access to local variable m1 |
-| CSharp7.cs:114:38:114:45 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:114:43:114:44 | access to local variable m2 |
-| CSharp7.cs:114:49:114:67 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:114:50:114:58 | "DefUse2" |
-| CSharp7.cs:114:49:114:67 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:114:61:114:66 | (..., ...) |
-| CSharp7.cs:114:61:114:66 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:114:62:114:62 | 0 |
-| CSharp7.cs:114:61:114:66 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:114:65:114:65 | 1 |
-| CSharp7.cs:218:16:218:23 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 0 | CSharp7.cs:218:17:218:17 | 0 |
-| CSharp7.cs:218:16:218:23 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 1 | CSharp7.cs:218:20:218:22 | 0 |
-| CSharp7.cs:224:9:224:14 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 0 | CSharp7.cs:224:10:224:10 | _ |
-| CSharp7.cs:224:9:224:14 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 1 | CSharp7.cs:224:13:224:13 | _ |
-| CSharp7.cs:225:9:225:18 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 0 | CSharp7.cs:225:14:225:14 | Int32 x |
-| CSharp7.cs:225:9:225:18 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 1 | CSharp7.cs:225:17:225:17 | _ |
-| CSharp7.cs:226:9:226:18 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 0 | CSharp7.cs:226:10:226:10 | _ |
-| CSharp7.cs:226:9:226:18 | (..., ...) | CSharp7.cs:215:5:215:17 | (Int32,Double) | 1 | CSharp7.cs:226:17:226:17 | Double y |
-| CSharp7.cs:285:40:285:61 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:285:41:285:48 | access to property Key |
-| CSharp7.cs:285:40:285:61 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:285:51:285:60 | access to property Value |
-| CSharp7.cs:287:18:287:34 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:287:23:287:23 | Int32 a |
-| CSharp7.cs:287:18:287:34 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:287:33:287:33 | String b |
-| CSharp7.cs:289:18:289:31 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:289:23:289:23 | Int32 a |
-| CSharp7.cs:289:18:289:31 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:289:30:289:30 | String b |
-| CSharp7.cs:291:18:291:27 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:291:23:291:23 | Int32 a |
-| CSharp7.cs:291:18:291:27 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:291:26:291:26 | String b |
+| CSharp7.cs:64:16:64:27 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:64:20:64:20 | 1 |
+| CSharp7.cs:64:16:64:27 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:64:26:64:26 | 2 |
+| CSharp7.cs:69:9:69:22 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:69:14:69:14 | Int32 x |
+| CSharp7.cs:69:9:69:22 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:69:21:69:21 | Int32 y |
+| CSharp7.cs:71:9:71:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:71:10:71:10 | access to local variable x |
+| CSharp7.cs:71:9:71:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:71:13:71:13 | access to local variable y |
+| CSharp7.cs:73:9:73:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 0 | CSharp7.cs:73:10:73:10 | access to local variable x |
+| CSharp7.cs:73:9:73:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 1 | CSharp7.cs:73:13:73:13 | access to local variable y |
+| CSharp7.cs:73:9:73:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 2 | CSharp7.cs:73:16:73:22 | access to field Item1 |
+| CSharp7.cs:73:27:73:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 0 | CSharp7.cs:73:28:73:28 | 1 |
+| CSharp7.cs:73:27:73:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 1 | CSharp7.cs:73:31:73:31 | 2 |
+| CSharp7.cs:73:27:73:35 | (..., ...) | file://:0:0:0:0 | (Int32,Int32,Int32) | 2 | CSharp7.cs:73:34:73:34 | 3 |
+| CSharp7.cs:74:9:74:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:74:10:74:10 | access to local variable x |
+| CSharp7.cs:74:9:74:14 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:74:13:74:13 | access to local variable y |
+| CSharp7.cs:74:18:74:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:74:19:74:19 | access to local variable x |
+| CSharp7.cs:74:18:74:23 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:74:22:74:22 | access to local variable y |
+| CSharp7.cs:74:27:74:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:74:28:74:28 | 1 |
+| CSharp7.cs:74:27:74:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:74:31:74:31 | 2 |
+| CSharp7.cs:75:9:75:31 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:75:14:75:14 | Int32 a |
+| CSharp7.cs:75:9:75:31 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:75:17:75:30 | (..., ...) |
+| CSharp7.cs:75:17:75:30 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:75:22:75:22 | Int32 b |
+| CSharp7.cs:75:17:75:30 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:75:29:75:29 | Int32 c |
+| CSharp7.cs:75:35:75:40 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:75:36:75:36 | 1 |
+| CSharp7.cs:75:35:75:40 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:75:39:75:39 | access to local variable z |
+| CSharp7.cs:76:9:76:19 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:76:10:76:10 | access to local variable a |
+| CSharp7.cs:76:9:76:19 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:76:13:76:18 | (..., ...) |
+| CSharp7.cs:76:13:76:18 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:76:14:76:14 | access to local variable b |
+| CSharp7.cs:76:13:76:18 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:76:17:76:17 | access to local variable c |
+| CSharp7.cs:76:23:76:33 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 0 | CSharp7.cs:76:24:76:24 | access to local variable b |
+| CSharp7.cs:76:23:76:33 | (..., ...) | file://:0:0:0:0 | (Int32,(Int32,Int32)) | 1 | CSharp7.cs:76:27:76:32 | (..., ...) |
+| CSharp7.cs:76:27:76:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:76:28:76:28 | access to local variable c |
+| CSharp7.cs:76:27:76:32 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:76:31:76:31 | access to local variable a |
+| CSharp7.cs:77:9:77:18 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:77:14:77:14 | String i |
+| CSharp7.cs:77:9:77:18 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:77:17:77:17 | Int32 j |
+| CSharp7.cs:77:22:77:28 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:77:23:77:24 | "" |
+| CSharp7.cs:77:22:77:28 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:77:27:77:27 | access to local variable x |
+| CSharp7.cs:82:16:82:24 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:82:20:82:20 | access to parameter x |
+| CSharp7.cs:82:16:82:24 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:82:23:82:23 | 2 |
+| CSharp7.cs:87:18:87:34 | (..., ...) | CSharp7.cs:87:18:87:34 | (String,String) | 0 | CSharp7.cs:87:19:87:27 | "tainted" |
+| CSharp7.cs:87:18:87:34 | (..., ...) | CSharp7.cs:87:18:87:34 | (String,String) | 1 | CSharp7.cs:87:30:87:33 | "X2" |
+| CSharp7.cs:88:9:88:24 | (..., ...) | CSharp7.cs:87:18:87:34 | (String,String) | 0 | CSharp7.cs:88:14:88:15 | String t2 |
+| CSharp7.cs:88:9:88:24 | (..., ...) | CSharp7.cs:87:18:87:34 | (String,String) | 1 | CSharp7.cs:88:22:88:23 | String t3 |
+| CSharp7.cs:95:18:95:38 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:95:19:95:19 | 1 |
+| CSharp7.cs:95:18:95:38 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:95:22:95:37 | "TupleExprNode1" |
+| CSharp7.cs:96:18:96:43 | (..., ...) | CSharp7.cs:96:18:96:43 | (Int32,(String,Int32)) | 0 | CSharp7.cs:96:19:96:19 | 1 |
+| CSharp7.cs:96:18:96:43 | (..., ...) | CSharp7.cs:96:18:96:43 | (Int32,(String,Int32)) | 1 | CSharp7.cs:96:22:96:42 | (..., ...) |
+| CSharp7.cs:96:22:96:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:96:23:96:38 | "TupleExprNode2" |
+| CSharp7.cs:96:22:96:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:96:41:96:41 | 2 |
+| CSharp7.cs:101:18:101:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:101:19:101:38 | "TupleMemberAccess1" |
+| CSharp7.cs:101:18:101:42 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:101:41:101:41 | 0 |
+| CSharp7.cs:102:18:102:47 | (..., ...) | CSharp7.cs:96:18:96:43 | (Int32,(String,Int32)) | 0 | CSharp7.cs:102:19:102:19 | 0 |
+| CSharp7.cs:102:18:102:47 | (..., ...) | CSharp7.cs:96:18:96:43 | (Int32,(String,Int32)) | 1 | CSharp7.cs:102:22:102:46 | (..., ...) |
+| CSharp7.cs:102:22:102:46 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 0 | CSharp7.cs:102:23:102:42 | "TupleMemberAccess2" |
+| CSharp7.cs:102:22:102:46 | (..., ...) | file://:0:0:0:0 | (String,Int32) | 1 | CSharp7.cs:102:45:102:45 | 1 |
+| CSharp7.cs:107:9:107:24 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:107:14:107:15 | String m1 |
+| CSharp7.cs:107:9:107:24 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:107:22:107:23 | (Int32,Int32) m2 |
+| CSharp7.cs:107:28:107:46 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:107:29:107:37 | "DefUse1" |
+| CSharp7.cs:107:28:107:46 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:107:40:107:45 | (..., ...) |
+| CSharp7.cs:107:40:107:45 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:107:41:107:41 | 0 |
+| CSharp7.cs:107:40:107:45 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:107:44:107:44 | 1 |
+| CSharp7.cs:110:9:110:22 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:110:10:110:11 | access to local variable m3 |
+| CSharp7.cs:110:9:110:22 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:110:14:110:21 | (..., ...) |
+| CSharp7.cs:110:14:110:21 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:110:15:110:16 | access to local variable m4 |
+| CSharp7.cs:110:14:110:21 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:110:19:110:20 | access to local variable m5 |
+| CSharp7.cs:110:26:110:33 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:110:27:110:28 | access to local variable m1 |
+| CSharp7.cs:110:26:110:33 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:110:31:110:32 | access to local variable m2 |
+| CSharp7.cs:112:9:112:34 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:112:14:112:15 | String m7 |
+| CSharp7.cs:112:9:112:34 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:112:18:112:33 | (..., ...) |
+| CSharp7.cs:112:18:112:33 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:112:23:112:24 | Int32 m8 |
+| CSharp7.cs:112:18:112:33 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:112:31:112:32 | Int32 m9 |
+| CSharp7.cs:112:38:112:45 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:112:39:112:40 | access to local variable m1 |
+| CSharp7.cs:112:38:112:45 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:112:43:112:44 | access to local variable m2 |
+| CSharp7.cs:112:49:112:67 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 0 | CSharp7.cs:112:50:112:58 | "DefUse2" |
+| CSharp7.cs:112:49:112:67 | (..., ...) | file://:0:0:0:0 | (String,(Int32,Int32)) | 1 | CSharp7.cs:112:61:112:66 | (..., ...) |
+| CSharp7.cs:112:61:112:66 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 0 | CSharp7.cs:112:62:112:62 | 0 |
+| CSharp7.cs:112:61:112:66 | (..., ...) | file://:0:0:0:0 | (Int32,Int32) | 1 | CSharp7.cs:112:65:112:65 | 1 |
+| CSharp7.cs:216:16:216:23 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 0 | CSharp7.cs:216:17:216:17 | 0 |
+| CSharp7.cs:216:16:216:23 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 1 | CSharp7.cs:216:20:216:22 | 0 |
+| CSharp7.cs:222:9:222:14 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 0 | CSharp7.cs:222:10:222:10 | _ |
+| CSharp7.cs:222:9:222:14 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 1 | CSharp7.cs:222:13:222:13 | _ |
+| CSharp7.cs:223:9:223:18 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 0 | CSharp7.cs:223:14:223:14 | Int32 x |
+| CSharp7.cs:223:9:223:18 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 1 | CSharp7.cs:223:17:223:17 | _ |
+| CSharp7.cs:224:9:224:18 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 0 | CSharp7.cs:224:10:224:10 | _ |
+| CSharp7.cs:224:9:224:18 | (..., ...) | CSharp7.cs:213:5:213:17 | (Int32,Double) | 1 | CSharp7.cs:224:17:224:17 | Double y |
+| CSharp7.cs:283:40:283:61 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:283:41:283:48 | access to property Key |
+| CSharp7.cs:283:40:283:61 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:283:51:283:60 | access to property Value |
+| CSharp7.cs:285:18:285:34 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:285:23:285:23 | Int32 a |
+| CSharp7.cs:285:18:285:34 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:285:33:285:33 | String b |
+| CSharp7.cs:287:18:287:31 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:287:23:287:23 | Int32 a |
+| CSharp7.cs:287:18:287:31 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:287:30:287:30 | String b |
+| CSharp7.cs:289:18:289:27 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 0 | CSharp7.cs:289:23:289:23 | Int32 a |
+| CSharp7.cs:289:18:289:27 | (..., ...) | file://:0:0:0:0 | (Int32,String) | 1 | CSharp7.cs:289:26:289:26 | String b |
diff --git a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected
index dfb6bca2890..963efc242f1 100644
--- a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected
+++ b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected
@@ -1,10 +1,10 @@
-| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:98:19:98:19 | Item1 |
-| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:98:22:98:42 | Item2 |
-| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:215:6:215:8 | Item1 |
-| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:215:11:215:16 | Item2 |
-| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:64:10:64:10 | Item1 |
-| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:64:17:64:17 | Item2 |
-| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:84:17:84:17 | Item1 |
-| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:84:23:84:23 | Item2 |
-| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:89:19:89:27 | Item1 |
-| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:89:30:89:33 | Item2 |
+| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:96:19:96:19 | Item1 |
+| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:96:22:96:42 | Item2 |
+| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:213:6:213:8 | Item1 |
+| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:213:11:213:16 | Item2 |
+| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:62:10:62:10 | Item1 |
+| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:62:17:62:17 | Item2 |
+| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:82:17:82:17 | Item1 |
+| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:82:23:82:23 | Item2 |
+| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:87:19:87:27 | Item1 |
+| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:87:30:87:33 | Item2 |
diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase1.expected b/csharp/ql/test/library-tests/csharp7/TypeCase1.expected
index f5feda6b24b..2c01427e544 100644
--- a/csharp/ql/test/library-tests/csharp7/TypeCase1.expected
+++ b/csharp/ql/test/library-tests/csharp7/TypeCase1.expected
@@ -1,9 +1,9 @@
-| CSharp7.cs:252:13:252:23 | case ...: |
-| CSharp7.cs:254:13:254:31 | case ...: |
-| CSharp7.cs:256:13:256:41 | case ...: |
-| CSharp7.cs:259:13:259:36 | case ...: |
-| CSharp7.cs:262:13:262:24 | case ...: |
-| CSharp7.cs:265:13:265:27 | case ...: |
-| CSharp7.cs:268:13:268:26 | case ...: |
-| CSharp7.cs:271:13:271:24 | case ...: |
-| CSharp7.cs:273:13:273:20 | default: |
+| CSharp7.cs:250:13:250:23 | case ...: |
+| CSharp7.cs:252:13:252:31 | case ...: |
+| CSharp7.cs:254:13:254:41 | case ...: |
+| CSharp7.cs:257:13:257:36 | case ...: |
+| CSharp7.cs:260:13:260:24 | case ...: |
+| CSharp7.cs:263:13:263:27 | case ...: |
+| CSharp7.cs:266:13:266:26 | case ...: |
+| CSharp7.cs:269:13:269:24 | case ...: |
+| CSharp7.cs:271:13:271:20 | default: |
diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase2.expected b/csharp/ql/test/library-tests/csharp7/TypeCase2.expected
index bace5da4c04..a11b6a5408a 100644
--- a/csharp/ql/test/library-tests/csharp7/TypeCase2.expected
+++ b/csharp/ql/test/library-tests/csharp7/TypeCase2.expected
@@ -1,4 +1,4 @@
-| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:18:259:23 | Int32 i2 | Int32 | false |
-| CSharp7.cs:262:13:262:24 | case ...: | CSharp7.cs:262:18:262:23 | Int32 i3 | Int32 | false |
-| CSharp7.cs:265:13:265:27 | case ...: | CSharp7.cs:265:18:265:26 | String s2 | String | false |
-| CSharp7.cs:271:13:271:24 | case ...: | CSharp7.cs:271:18:271:23 | Object v2 | Object | true |
+| CSharp7.cs:257:13:257:36 | case ...: | CSharp7.cs:257:18:257:23 | Int32 i2 | Int32 | false |
+| CSharp7.cs:260:13:260:24 | case ...: | CSharp7.cs:260:18:260:23 | Int32 i3 | Int32 | false |
+| CSharp7.cs:263:13:263:27 | case ...: | CSharp7.cs:263:18:263:26 | String s2 | String | false |
+| CSharp7.cs:269:13:269:24 | case ...: | CSharp7.cs:269:18:269:23 | Object v2 | Object | true |
diff --git a/csharp/ql/test/library-tests/csharp7/TypeCase3.expected b/csharp/ql/test/library-tests/csharp7/TypeCase3.expected
index abab42820f8..4a190509b94 100644
--- a/csharp/ql/test/library-tests/csharp7/TypeCase3.expected
+++ b/csharp/ql/test/library-tests/csharp7/TypeCase3.expected
@@ -1 +1 @@
-| CSharp7.cs:259:13:259:36 | case ...: | CSharp7.cs:259:30:259:35 | ... > ... |
+| CSharp7.cs:257:13:257:36 | case ...: | CSharp7.cs:257:30:257:35 | ... > ... |
diff --git a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected
index 8629d9d496c..a7cd5bf945f 100644
--- a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected
@@ -1,7 +1,7 @@
-| CSharp7.cs:133:9:133:42 | f2 | 0 | CSharp7.cs:133:14:133:14 | T |
-| CSharp7.cs:133:9:133:42 | f2 | 1 | CSharp7.cs:133:17:133:17 | U |
-| CSharp7.cs:161:9:161:24 | f | 0 | CSharp7.cs:161:15:161:15 | T |
-| CSharp7.cs:162:9:162:25 | g | 0 | CSharp7.cs:162:13:162:13 | T |
-| CSharp7.cs:164:9:169:9 | h | 0 | CSharp7.cs:164:13:164:13 | T |
-| CSharp7.cs:164:9:169:9 | h | 1 | CSharp7.cs:164:16:164:16 | U |
-| CSharp7.cs:166:13:166:43 | f2 | 0 | CSharp7.cs:166:20:166:20 | S |
+| CSharp7.cs:131:9:131:42 | f2 | 0 | CSharp7.cs:131:14:131:14 | T |
+| CSharp7.cs:131:9:131:42 | f2 | 1 | CSharp7.cs:131:17:131:17 | U |
+| CSharp7.cs:159:9:159:24 | f | 0 | CSharp7.cs:159:15:159:15 | T |
+| CSharp7.cs:160:9:160:25 | g | 0 | CSharp7.cs:160:13:160:13 | T |
+| CSharp7.cs:162:9:167:9 | h | 0 | CSharp7.cs:162:13:162:13 | T |
+| CSharp7.cs:162:9:167:9 | h | 1 | CSharp7.cs:162:16:162:16 | U |
+| CSharp7.cs:164:13:164:43 | f2 | 0 | CSharp7.cs:164:20:164:20 | S |
diff --git a/csharp/ql/test/library-tests/csharp7/options b/csharp/ql/test/library-tests/csharp7/options
new file mode 100644
index 00000000000..c281ba1ee1f
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp7/options
@@ -0,0 +1 @@
+semmle-extractor-options: /r:System.Linq.dll
diff --git a/csharp/ql/test/library-tests/csharp8/AsyncStreams.cs b/csharp/ql/test/library-tests/csharp8/AsyncStreams.cs
index a5e52adeecb..343df82d97c 100644
--- a/csharp/ql/test/library-tests/csharp8/AsyncStreams.cs
+++ b/csharp/ql/test/library-tests/csharp8/AsyncStreams.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /r:System.Threading.Tasks.dll /r:System.Threading.Tasks.Extensions.dll /r:netstandard.dll /langversion:preview
-
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.expected b/csharp/ql/test/library-tests/csharp8/PrintAst.expected
index 3a4cad07fc6..9df8e105c39 100644
--- a/csharp/ql/test/library-tests/csharp8/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp8/PrintAst.expected
@@ -15,63 +15,63 @@ AlternateInterpolatedStrings.cs:
# 6| 0: [StringLiteral] "C:"
# 6| 1: [IntLiteral] 12
AsyncStreams.cs:
-# 8| [Class] AsyncStreams
-# 10| 5: [Method] Items
-# 10| -1: [TypeMention] IAsyncEnumerable
-# 10| 1: [TypeMention] int
-# 10| 4: [BlockStmt] {...}
-# 11| 0: [YieldReturnStmt] yield return ...;
-# 11| 0: [IntLiteral] 1
-# 12| 1: [YieldReturnStmt] yield return ...;
-# 12| 0: [IntLiteral] 2
-# 13| 2: [ExprStmt] ...;
-# 13| 0: [AwaitExpr] await ...
-# 13| 0: [MethodCall] call to method Delay
-# 13| -1: [TypeAccess] access to type Task
-# 13| 0: [TypeMention] Task
-# 13| 0: [IntLiteral] 1000
-# 14| 3: [YieldReturnStmt] yield return ...;
-# 14| 0: [IntLiteral] 3
-# 17| 6: [Method] F
-# 17| -1: [TypeMention] Void
-# 18| 4: [BlockStmt] {...}
-# 19| 0: [ForeachStmt] foreach (... ... in ...) ...
-# 19| 0: [LocalVariableDeclExpr] Int32 item
-# 19| 0: [TypeMention] int
-# 19| 1: [MethodCall] call to method Items
-# 20| 2: [ExprStmt] ...;
-# 20| 0: [MethodCall] call to method WriteLine
-# 20| -1: [TypeAccess] access to type Console
-# 20| 0: [TypeMention] Console
-# 20| 0: [LocalVariableAccess] access to local variable item
-# 24| [NamespaceDeclaration] namespace ... { ... }
-# 26| 1: [Interface] IAsyncDisposable
-# 28| 4: [Method] DisposeAsync
-# 28| -1: [TypeMention] ValueTask
-# 32| [NamespaceDeclaration] namespace ... { ... }
-# 34| 1: [Interface] IAsyncEnumerable<>
+# 6| [Class] AsyncStreams
+# 8| 5: [Method] Items
+# 8| -1: [TypeMention] IAsyncEnumerable
+# 8| 1: [TypeMention] int
+# 8| 4: [BlockStmt] {...}
+# 9| 0: [YieldReturnStmt] yield return ...;
+# 9| 0: [IntLiteral] 1
+# 10| 1: [YieldReturnStmt] yield return ...;
+# 10| 0: [IntLiteral] 2
+# 11| 2: [ExprStmt] ...;
+# 11| 0: [AwaitExpr] await ...
+# 11| 0: [MethodCall] call to method Delay
+# 11| -1: [TypeAccess] access to type Task
+# 11| 0: [TypeMention] Task
+# 11| 0: [IntLiteral] 1000
+# 12| 3: [YieldReturnStmt] yield return ...;
+# 12| 0: [IntLiteral] 3
+# 15| 6: [Method] F
+# 15| -1: [TypeMention] Void
+# 16| 4: [BlockStmt] {...}
+# 17| 0: [ForeachStmt] foreach (... ... in ...) ...
+# 17| 0: [LocalVariableDeclExpr] Int32 item
+# 17| 0: [TypeMention] int
+# 17| 1: [MethodCall] call to method Items
+# 18| 2: [ExprStmt] ...;
+# 18| 0: [MethodCall] call to method WriteLine
+# 18| -1: [TypeAccess] access to type Console
+# 18| 0: [TypeMention] Console
+# 18| 0: [LocalVariableAccess] access to local variable item
+# 22| [NamespaceDeclaration] namespace ... { ... }
+# 24| 1: [Interface] IAsyncDisposable
+# 26| 4: [Method] DisposeAsync
+# 26| -1: [TypeMention] ValueTask
+# 30| [NamespaceDeclaration] namespace ... { ... }
+# 32| 1: [Interface] IAsyncEnumerable<>
#-----| 1: (Type parameters)
-# 34| 0: [TypeParameter] T
-# 36| 4: [Method] GetAsyncEnumerator
-# 36| -1: [TypeMention] IAsyncEnumerator
-# 36| 1: [TypeMention] T
+# 32| 0: [TypeParameter] T
+# 34| 4: [Method] GetAsyncEnumerator
+# 34| -1: [TypeMention] IAsyncEnumerator
+# 34| 1: [TypeMention] T
#-----| 2: (Parameters)
-# 36| 0: [Parameter] cancellationToken
-# 36| -1: [TypeMention] CancellationToken
-# 36| 1: [DefaultValueExpr] default(...)
-# 36| 0: [TypeAccess] access to type CancellationToken
-# 36| 0: [TypeMention] CancellationToken
-# 39| 2: [Interface] IAsyncEnumerator<>
+# 34| 0: [Parameter] cancellationToken
+# 34| -1: [TypeMention] CancellationToken
+# 34| 1: [DefaultValueExpr] default(...)
+# 34| 0: [TypeAccess] access to type CancellationToken
+# 34| 0: [TypeMention] CancellationToken
+# 37| 2: [Interface] IAsyncEnumerator<>
#-----| 1: (Type parameters)
-# 39| 0: [TypeParameter] T
+# 37| 0: [TypeParameter] T
#-----| 3: (Base types)
-# 39| 1: [TypeMention] IAsyncDisposable
-# 41| 4: [Property] Current
-# 41| -1: [TypeMention] T
-# 41| 3: [Getter] get_Current
-# 42| 5: [Method] MoveNextAsync
-# 42| -1: [TypeMention] ValueTask
-# 42| 1: [TypeMention] bool
+# 37| 1: [TypeMention] IAsyncDisposable
+# 39| 4: [Property] Current
+# 39| -1: [TypeMention] T
+# 39| 3: [Getter] get_Current
+# 40| 5: [Method] MoveNextAsync
+# 40| -1: [TypeMention] ValueTask
+# 40| 1: [TypeMention] bool
DefaultInterfaceMethods.cs:
# 3| [Interface] IPerson
# 5| 4: [Property] Name
@@ -670,35 +670,35 @@ NullableRefTypes.cs:
# 225| 13: [Field] Field
# 225| -1: [TypeMention] string
StaticLocalFunctions.cs:
-# 5| [Class] StaticLocalFunctions
-# 7| 5: [Method] Fn
-# 7| -1: [TypeMention] int
+# 3| [Class] StaticLocalFunctions
+# 5| 5: [Method] Fn
+# 5| -1: [TypeMention] int
#-----| 2: (Parameters)
-# 7| 0: [Parameter] x
-# 7| -1: [TypeMention] int
-# 8| 4: [BlockStmt] {...}
-# 9| 0: [LocalFunctionStmt] I(...)
-# 9| 0: [LocalFunction] I
+# 5| 0: [Parameter] x
+# 5| -1: [TypeMention] int
+# 6| 4: [BlockStmt] {...}
+# 7| 0: [LocalFunctionStmt] I(...)
+# 7| 0: [LocalFunction] I
#-----| 2: (Parameters)
-# 9| 0: [Parameter] y
-# 9| -1: [TypeMention] int
-# 9| 4: [ParameterAccess] access to parameter y
-# 10| 1: [LocalFunctionStmt] J(...)
-# 10| 0: [LocalFunction] J
+# 7| 0: [Parameter] y
+# 7| -1: [TypeMention] int
+# 7| 4: [ParameterAccess] access to parameter y
+# 8| 1: [LocalFunctionStmt] J(...)
+# 8| 0: [LocalFunction] J
#-----| 2: (Parameters)
-# 10| 0: [Parameter] y
-# 10| -1: [TypeMention] int
-# 10| 4: [AddExpr] ... + ...
-# 10| 0: [ParameterAccess] access to parameter x
-# 10| 1: [ParameterAccess] access to parameter y
-# 11| 2: [ReturnStmt] return ...;
-# 11| 0: [AddExpr] ... + ...
-# 11| 0: [LocalFunctionCall] call to local function I
-# 11| -1: [LocalFunctionAccess] access to local function I
-# 11| 0: [ParameterAccess] access to parameter x
-# 11| 1: [LocalFunctionCall] call to local function J
-# 11| -1: [LocalFunctionAccess] access to local function J
-# 11| 0: [ParameterAccess] access to parameter x
+# 8| 0: [Parameter] y
+# 8| -1: [TypeMention] int
+# 8| 4: [AddExpr] ... + ...
+# 8| 0: [ParameterAccess] access to parameter x
+# 8| 1: [ParameterAccess] access to parameter y
+# 9| 2: [ReturnStmt] return ...;
+# 9| 0: [AddExpr] ... + ...
+# 9| 0: [LocalFunctionCall] call to local function I
+# 9| -1: [LocalFunctionAccess] access to local function I
+# 9| 0: [ParameterAccess] access to parameter x
+# 9| 1: [LocalFunctionCall] call to local function J
+# 9| -1: [LocalFunctionAccess] access to local function J
+# 9| 0: [ParameterAccess] access to parameter x
UnmanagedGenericStructs.cs:
# 3| [Struct] S<,>
#-----| 1: (Type parameters)
@@ -1236,97 +1236,97 @@ patterns.cs:
# 164| -1: [TypeMention] Void
# 165| 4: [BlockStmt] {...}
ranges.cs:
-# 5| [Class] Ranges
-# 7| 5: [Method] F
-# 7| -1: [TypeMention] Void
-# 8| 4: [BlockStmt] {...}
-# 9| 0: [LocalVariableDeclStmt] ... ...;
-# 9| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ...
+# 3| [Class] Ranges
+# 5| 5: [Method] F
+# 5| -1: [TypeMention] Void
+# 6| 4: [BlockStmt] {...}
+# 7| 0: [LocalVariableDeclStmt] ... ...;
+# 7| 0: [LocalVariableDeclAndInitExpr] Int32[] array = ...
+# 7| -1: [TypeMention] Int32[]
+# 7| 0: [LocalVariableAccess] access to local variable array
+# 7| 1: [ArrayCreation] array creation of type Int32[]
+# 7| -2: [TypeMention] Int32[]
+# 7| 1: [TypeMention] int
+# 7| -1: [ArrayInitializer] { ..., ... }
+# 7| 0: [IntLiteral] 1
+# 7| 1: [IntLiteral] 2
+# 7| 2: [IntLiteral] 3
+# 7| 3: [IntLiteral] 4
+# 9| 1: [LocalVariableDeclStmt] ... ...;
+# 9| 0: [LocalVariableDeclAndInitExpr] Int32[] slice1 = ...
# 9| -1: [TypeMention] Int32[]
-# 9| 0: [LocalVariableAccess] access to local variable array
-# 9| 1: [ArrayCreation] array creation of type Int32[]
-# 9| -2: [TypeMention] Int32[]
-# 9| 1: [TypeMention] int
-# 9| -1: [ArrayInitializer] { ..., ... }
-# 9| 0: [IntLiteral] 1
-# 9| 1: [IntLiteral] 2
-# 9| 2: [IntLiteral] 3
-# 9| 3: [IntLiteral] 4
-# 11| 1: [LocalVariableDeclStmt] ... ...;
-# 11| 0: [LocalVariableDeclAndInitExpr] Int32[] slice1 = ...
-# 11| -1: [TypeMention] Int32[]
-# 11| 0: [LocalVariableAccess] access to local variable slice1
-# 11| 1: [ArrayAccess] access to array element
-# 11| -1: [LocalVariableAccess] access to local variable array
-# 11| 0: [RangeExpr] ... .. ...
-# 11| 0: [OperatorCall] call to operator implicit conversion
-# 11| 0: [IntLiteral] 1
-# 11| 1: [OperatorCall] call to operator implicit conversion
-# 11| 0: [IntLiteral] 3
-# 12| 2: [LocalVariableDeclStmt] ... ...;
-# 12| 0: [LocalVariableDeclAndInitExpr] Int32[] slice2 = ...
+# 9| 0: [LocalVariableAccess] access to local variable slice1
+# 9| 1: [ArrayAccess] access to array element
+# 9| -1: [LocalVariableAccess] access to local variable array
+# 9| 0: [RangeExpr] ... .. ...
+# 9| 0: [OperatorCall] call to operator implicit conversion
+# 9| 0: [IntLiteral] 1
+# 9| 1: [OperatorCall] call to operator implicit conversion
+# 9| 0: [IntLiteral] 3
+# 10| 2: [LocalVariableDeclStmt] ... ...;
+# 10| 0: [LocalVariableDeclAndInitExpr] Int32[] slice2 = ...
+# 10| -1: [TypeMention] Int32[]
+# 10| 0: [LocalVariableAccess] access to local variable slice2
+# 10| 1: [ArrayAccess] access to array element
+# 10| -1: [LocalVariableAccess] access to local variable array
+# 10| 0: [RangeExpr] ... .. ...
+# 10| 0: [OperatorCall] call to operator implicit conversion
+# 10| 0: [IntLiteral] 0
+# 10| 1: [IndexExpr] ^...
+# 10| 0: [IntLiteral] 1
+# 11| 3: [LocalVariableDeclStmt] ... ...;
+# 11| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
+# 11| -1: [TypeMention] int
+# 11| 0: [LocalVariableAccess] access to local variable x
+# 11| 1: [IntLiteral] 2
+# 11| 1: [LocalVariableDeclAndInitExpr] Int32 y = ...
+# 11| -1: [TypeMention] int
+# 11| 0: [LocalVariableAccess] access to local variable y
+# 11| 1: [IntLiteral] 3
+# 12| 4: [LocalVariableDeclStmt] ... ...;
+# 12| 0: [LocalVariableDeclAndInitExpr] Int32[] slice3 = ...
# 12| -1: [TypeMention] Int32[]
-# 12| 0: [LocalVariableAccess] access to local variable slice2
+# 12| 0: [LocalVariableAccess] access to local variable slice3
# 12| 1: [ArrayAccess] access to array element
# 12| -1: [LocalVariableAccess] access to local variable array
# 12| 0: [RangeExpr] ... .. ...
# 12| 0: [OperatorCall] call to operator implicit conversion
-# 12| 0: [IntLiteral] 0
-# 12| 1: [IndexExpr] ^...
-# 12| 0: [IntLiteral] 1
-# 13| 3: [LocalVariableDeclStmt] ... ...;
-# 13| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
-# 13| -1: [TypeMention] int
-# 13| 0: [LocalVariableAccess] access to local variable x
-# 13| 1: [IntLiteral] 2
-# 13| 1: [LocalVariableDeclAndInitExpr] Int32 y = ...
-# 13| -1: [TypeMention] int
-# 13| 0: [LocalVariableAccess] access to local variable y
-# 13| 1: [IntLiteral] 3
-# 14| 4: [LocalVariableDeclStmt] ... ...;
-# 14| 0: [LocalVariableDeclAndInitExpr] Int32[] slice3 = ...
+# 12| 0: [LocalVariableAccess] access to local variable x
+# 12| 1: [OperatorCall] call to operator implicit conversion
+# 12| 0: [LocalVariableAccess] access to local variable y
+# 13| 5: [LocalVariableDeclStmt] ... ...;
+# 13| 0: [LocalVariableDeclAndInitExpr] Int32[] slice4 = ...
+# 13| -1: [TypeMention] Int32[]
+# 13| 0: [LocalVariableAccess] access to local variable slice4
+# 13| 1: [ArrayAccess] access to array element
+# 13| -1: [LocalVariableAccess] access to local variable array
+# 13| 0: [RangeExpr] ... .. ...
+# 13| 1: [OperatorCall] call to operator implicit conversion
+# 13| 0: [LocalVariableAccess] access to local variable y
+# 14| 6: [LocalVariableDeclStmt] ... ...;
+# 14| 0: [LocalVariableDeclAndInitExpr] Int32[] slice5 = ...
# 14| -1: [TypeMention] Int32[]
-# 14| 0: [LocalVariableAccess] access to local variable slice3
+# 14| 0: [LocalVariableAccess] access to local variable slice5
# 14| 1: [ArrayAccess] access to array element
# 14| -1: [LocalVariableAccess] access to local variable array
# 14| 0: [RangeExpr] ... .. ...
# 14| 0: [OperatorCall] call to operator implicit conversion
# 14| 0: [LocalVariableAccess] access to local variable x
-# 14| 1: [OperatorCall] call to operator implicit conversion
-# 14| 0: [LocalVariableAccess] access to local variable y
-# 15| 5: [LocalVariableDeclStmt] ... ...;
-# 15| 0: [LocalVariableDeclAndInitExpr] Int32[] slice4 = ...
+# 15| 7: [LocalVariableDeclStmt] ... ...;
+# 15| 0: [LocalVariableDeclAndInitExpr] Int32[] slice6 = ...
# 15| -1: [TypeMention] Int32[]
-# 15| 0: [LocalVariableAccess] access to local variable slice4
+# 15| 0: [LocalVariableAccess] access to local variable slice6
# 15| 1: [ArrayAccess] access to array element
# 15| -1: [LocalVariableAccess] access to local variable array
# 15| 0: [RangeExpr] ... .. ...
-# 15| 1: [OperatorCall] call to operator implicit conversion
-# 15| 0: [LocalVariableAccess] access to local variable y
-# 16| 6: [LocalVariableDeclStmt] ... ...;
-# 16| 0: [LocalVariableDeclAndInitExpr] Int32[] slice5 = ...
+# 16| 8: [LocalVariableDeclStmt] ... ...;
+# 16| 0: [LocalVariableDeclAndInitExpr] Int32[] slice7 = ...
# 16| -1: [TypeMention] Int32[]
-# 16| 0: [LocalVariableAccess] access to local variable slice5
+# 16| 0: [LocalVariableAccess] access to local variable slice7
# 16| 1: [ArrayAccess] access to array element
# 16| -1: [LocalVariableAccess] access to local variable array
# 16| 0: [RangeExpr] ... .. ...
-# 16| 0: [OperatorCall] call to operator implicit conversion
-# 16| 0: [LocalVariableAccess] access to local variable x
-# 17| 7: [LocalVariableDeclStmt] ... ...;
-# 17| 0: [LocalVariableDeclAndInitExpr] Int32[] slice6 = ...
-# 17| -1: [TypeMention] Int32[]
-# 17| 0: [LocalVariableAccess] access to local variable slice6
-# 17| 1: [ArrayAccess] access to array element
-# 17| -1: [LocalVariableAccess] access to local variable array
-# 17| 0: [RangeExpr] ... .. ...
-# 18| 8: [LocalVariableDeclStmt] ... ...;
-# 18| 0: [LocalVariableDeclAndInitExpr] Int32[] slice7 = ...
-# 18| -1: [TypeMention] Int32[]
-# 18| 0: [LocalVariableAccess] access to local variable slice7
-# 18| 1: [ArrayAccess] access to array element
-# 18| -1: [LocalVariableAccess] access to local variable array
-# 18| 0: [RangeExpr] ... .. ...
-# 18| 0: [IndexExpr] ^...
-# 18| 0: [IntLiteral] 10
-# 18| 1: [IndexExpr] ^...
-# 18| 0: [IntLiteral] 5
+# 16| 0: [IndexExpr] ^...
+# 16| 0: [IntLiteral] 10
+# 16| 1: [IndexExpr] ^...
+# 16| 0: [IntLiteral] 5
diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs
index 3074565fc47..80829240dfe 100644
--- a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs
+++ b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /langversion:8.0
-
using System;
class StaticLocalFunctions
diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected
index c00c1b102cb..9c9fc2ee12f 100644
--- a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected
@@ -1,3 +1,3 @@
-| StaticLocalFunctions.cs:9:9:9:33 | I | private |
-| StaticLocalFunctions.cs:9:9:9:33 | I | static |
-| StaticLocalFunctions.cs:10:9:10:28 | J | private |
+| StaticLocalFunctions.cs:7:9:7:33 | I | private |
+| StaticLocalFunctions.cs:7:9:7:33 | I | static |
+| StaticLocalFunctions.cs:8:9:8:28 | J | private |
diff --git a/csharp/ql/test/library-tests/csharp8/options b/csharp/ql/test/library-tests/csharp8/options
new file mode 100644
index 00000000000..7672a4e8c6b
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp8/options
@@ -0,0 +1,2 @@
+semmle-extractor-options: /langversion:8.0
+semmle-extractor-options: /r:System.Threading.Tasks.dll /r:System.Threading.Tasks.Extensions.dll /r:netstandard.dll /langversion:preview
diff --git a/csharp/ql/test/library-tests/csharp8/ranges.cs b/csharp/ql/test/library-tests/csharp8/ranges.cs
index e076b9ac4d2..f11fa03cae3 100644
--- a/csharp/ql/test/library-tests/csharp8/ranges.cs
+++ b/csharp/ql/test/library-tests/csharp8/ranges.cs
@@ -1,5 +1,3 @@
-// semmle-extractor-options: /langversion:8.0
-
using System;
class Ranges
diff --git a/csharp/ql/test/library-tests/csharp8/ranges.expected b/csharp/ql/test/library-tests/csharp8/ranges.expected
index 914f8c82a35..529b872835e 100644
--- a/csharp/ql/test/library-tests/csharp8/ranges.expected
+++ b/csharp/ql/test/library-tests/csharp8/ranges.expected
@@ -1,24 +1,24 @@
indexes
-| ranges.cs:12:31:12:32 | ^... | ranges.cs:12:32:12:32 | 1 |
-| ranges.cs:18:28:18:30 | ^... | ranges.cs:18:29:18:30 | 10 |
-| ranges.cs:18:33:18:34 | ^... | ranges.cs:18:34:18:34 | 5 |
+| ranges.cs:10:31:10:32 | ^... | ranges.cs:10:32:10:32 | 1 |
+| ranges.cs:16:28:16:30 | ^... | ranges.cs:16:29:16:30 | 10 |
+| ranges.cs:16:33:16:34 | ^... | ranges.cs:16:34:16:34 | 5 |
ranges
-| ranges.cs:11:28:11:31 | ... .. ... |
-| ranges.cs:12:28:12:32 | ... .. ... |
-| ranges.cs:14:28:14:31 | ... .. ... |
-| ranges.cs:15:28:15:30 | ... .. ... |
-| ranges.cs:16:28:16:30 | ... .. ... |
-| ranges.cs:17:28:17:29 | ... .. ... |
-| ranges.cs:18:28:18:34 | ... .. ... |
+| ranges.cs:9:28:9:31 | ... .. ... |
+| ranges.cs:10:28:10:32 | ... .. ... |
+| ranges.cs:12:28:12:31 | ... .. ... |
+| ranges.cs:13:28:13:30 | ... .. ... |
+| ranges.cs:14:28:14:30 | ... .. ... |
+| ranges.cs:15:28:15:29 | ... .. ... |
+| ranges.cs:16:28:16:34 | ... .. ... |
rangeStart
-| ranges.cs:11:28:11:31 | ... .. ... | ranges.cs:11:28:11:28 | 1 |
-| ranges.cs:12:28:12:32 | ... .. ... | ranges.cs:12:28:12:28 | 0 |
-| ranges.cs:14:28:14:31 | ... .. ... | ranges.cs:14:28:14:28 | access to local variable x |
-| ranges.cs:16:28:16:30 | ... .. ... | ranges.cs:16:28:16:28 | access to local variable x |
-| ranges.cs:18:28:18:34 | ... .. ... | ranges.cs:18:28:18:30 | ^... |
+| ranges.cs:9:28:9:31 | ... .. ... | ranges.cs:9:28:9:28 | 1 |
+| ranges.cs:10:28:10:32 | ... .. ... | ranges.cs:10:28:10:28 | 0 |
+| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:28:12:28 | access to local variable x |
+| ranges.cs:14:28:14:30 | ... .. ... | ranges.cs:14:28:14:28 | access to local variable x |
+| ranges.cs:16:28:16:34 | ... .. ... | ranges.cs:16:28:16:30 | ^... |
rangeEnd
-| ranges.cs:11:28:11:31 | ... .. ... | ranges.cs:11:31:11:31 | 3 |
-| ranges.cs:12:28:12:32 | ... .. ... | ranges.cs:12:31:12:32 | ^... |
-| ranges.cs:14:28:14:31 | ... .. ... | ranges.cs:14:31:14:31 | access to local variable y |
-| ranges.cs:15:28:15:30 | ... .. ... | ranges.cs:15:30:15:30 | access to local variable y |
-| ranges.cs:18:28:18:34 | ... .. ... | ranges.cs:18:33:18:34 | ^... |
+| ranges.cs:9:28:9:31 | ... .. ... | ranges.cs:9:31:9:31 | 3 |
+| ranges.cs:10:28:10:32 | ... .. ... | ranges.cs:10:31:10:32 | ^... |
+| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:31:12:31 | access to local variable y |
+| ranges.cs:13:28:13:30 | ... .. ... | ranges.cs:13:30:13:30 | access to local variable y |
+| ranges.cs:16:28:16:34 | ... .. ... | ranges.cs:16:33:16:34 | ^... |
diff --git a/csharp/ql/test/library-tests/csharp9/AnonymousObjectCreation.cs b/csharp/ql/test/library-tests/csharp9/AnonymousObjectCreation.cs
index da10c241883..94510d4da50 100644
--- a/csharp/ql/test/library-tests/csharp9/AnonymousObjectCreation.cs
+++ b/csharp/ql/test/library-tests/csharp9/AnonymousObjectCreation.cs
@@ -24,4 +24,4 @@ public class AnonObj
{
List list = new();// { 1, 2, 3 }; todo: the initializer causes an extraction error
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/BinaryPattern.cs b/csharp/ql/test/library-tests/csharp9/BinaryPattern.cs
index 45570ed9695..dc18c6b3a9c 100644
--- a/csharp/ql/test/library-tests/csharp9/BinaryPattern.cs
+++ b/csharp/ql/test/library-tests/csharp9/BinaryPattern.cs
@@ -19,4 +19,4 @@ public class BinaryPattern
_ => "other"
};
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs b/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs
index ac39aae893d..870642fe0b2 100644
--- a/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs
+++ b/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs
@@ -6,4 +6,4 @@ class A
class B : A
{
public override B M1() { throw null; }
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/Discard.cs b/csharp/ql/test/library-tests/csharp9/Discard.cs
index 8da28e40ffc..9aeeda740d8 100644
--- a/csharp/ql/test/library-tests/csharp9/Discard.cs
+++ b/csharp/ql/test/library-tests/csharp9/Discard.cs
@@ -9,4 +9,4 @@ public class Discard
i = (int _, int _) => 42;
i = delegate (int _, int _) { return 0; };
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/FunctionPointer.cs b/csharp/ql/test/library-tests/csharp9/FunctionPointer.cs
index 3c51dcc1744..a295b3134ca 100644
--- a/csharp/ql/test/library-tests/csharp9/FunctionPointer.cs
+++ b/csharp/ql/test/library-tests/csharp9/FunctionPointer.cs
@@ -1,7 +1,5 @@
using System;
-
-
public class FnPointer
{
public unsafe static class Program
@@ -49,4 +47,4 @@ public class FnPointer
class A { }
class B : A { }
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected
index 2d2c60cecd8..e693fe3a09c 100644
--- a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected
+++ b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected
@@ -28,10 +28,10 @@ parameter
| file://:0:0:0:0 | delegate* stdcall | 1 | file://:0:0:0:0 | `1 | out object? |
| file://:0:0:0:0 | delegate* stdcall | 2 | file://:0:0:0:0 | `2 | T |
invocation
-| FunctionPointer.cs:19:21:19:43 | function pointer call |
-| FunctionPointer.cs:25:13:25:44 | function pointer call |
-| FunctionPointer.cs:31:29:31:57 | function pointer call |
-| FunctionPointer.cs:36:21:36:30 | function pointer call |
+| FunctionPointer.cs:17:21:17:43 | function pointer call |
+| FunctionPointer.cs:23:13:23:44 | function pointer call |
+| FunctionPointer.cs:29:29:29:57 | function pointer call |
+| FunctionPointer.cs:34:21:34:30 | function pointer call |
casts
-| FunctionPointer.cs:41:16:41:17 | (...) ... | file://:0:0:0:0 | delegate* default | file://:0:0:0:0 | delegate* default |
-| FunctionPointer.cs:46:16:46:17 | (...) ... | file://:0:0:0:0 | delegate* default | file://:0:0:0:0 | delegate* default |
+| FunctionPointer.cs:39:16:39:17 | (...) ... | file://:0:0:0:0 | delegate* default | file://:0:0:0:0 | delegate* default |
+| FunctionPointer.cs:44:16:44:17 | (...) ... | file://:0:0:0:0 | delegate* default | file://:0:0:0:0 | delegate* default |
diff --git a/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs b/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs
index 6b8958d7fbd..54572be1ed9 100644
--- a/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs
+++ b/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs
@@ -1,7 +1,5 @@
/*
Global statements are not allowed in 'library' target.
-
- semmle-extractor-options: --standalone
*/
using System;
@@ -22,4 +20,4 @@ public class Attr : Attribute
{
Console.WriteLine("3");
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs b/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs
index e5a27113566..86e4119ef8a 100644
--- a/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs
+++ b/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs
@@ -34,4 +34,4 @@ public class C1
Prop0 = 0
};
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/LambdaModifier.cs b/csharp/ql/test/library-tests/csharp9/LambdaModifier.cs
index 2895b0beed1..1207da7f6bf 100644
--- a/csharp/ql/test/library-tests/csharp9/LambdaModifier.cs
+++ b/csharp/ql/test/library-tests/csharp9/LambdaModifier.cs
@@ -14,4 +14,4 @@ public class Class1
await Task.Run(async () => { await Task.CompletedTask; });
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/LocalFunction.cs b/csharp/ql/test/library-tests/csharp9/LocalFunction.cs
index 38d4c93d9a7..b5f5f49b490 100644
--- a/csharp/ql/test/library-tests/csharp9/LocalFunction.cs
+++ b/csharp/ql/test/library-tests/csharp9/LocalFunction.cs
@@ -26,4 +26,4 @@ public class LocalFunction
dup(true, 42);
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected
index c57ece05e59..aa1795eaf84 100644
--- a/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected
+++ b/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected
@@ -1,7 +1,7 @@
noBody
| LocalFunction.cs:16:9:16:41 | localExtern |
localFunctionModifier
-| GlobalStmt.cs:15:1:17:1 | M | private |
+| GlobalStmt.cs:13:1:15:1 | M | private |
| LambdaModifier.cs:8:9:8:36 | m | private |
| LocalFunction.cs:9:9:12:9 | mul | async |
| LocalFunction.cs:9:9:12:9 | mul | private |
diff --git a/csharp/ql/test/library-tests/csharp9/NativeInt.cs b/csharp/ql/test/library-tests/csharp9/NativeInt.cs
index 0b636178bc8..7780d78f509 100644
--- a/csharp/ql/test/library-tests/csharp9/NativeInt.cs
+++ b/csharp/ql/test/library-tests/csharp9/NativeInt.cs
@@ -24,4 +24,4 @@ public class NativeInt
var test6 = (x + y).GetType(); // System.IntPtr
var test7 = (x + v).GetType(); // System.Int64
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/ParenthesizedPattern.cs b/csharp/ql/test/library-tests/csharp9/ParenthesizedPattern.cs
index f40d9f714d3..dbf4a732beb 100644
--- a/csharp/ql/test/library-tests/csharp9/ParenthesizedPattern.cs
+++ b/csharp/ql/test/library-tests/csharp9/ParenthesizedPattern.cs
@@ -15,7 +15,6 @@ class ParenthesizedPattern
}
}
-
void M2(object o)
{
var r = o switch
diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected
index 6da09ceb287..68e692e6762 100644
--- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected
+++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected
@@ -285,158 +285,158 @@ ForeachExtension.cs:
# 46| 2: [YieldReturnStmt] yield return ...;
# 46| 0: [IntLiteral] 1
FunctionPointer.cs:
-# 5| [Class] FnPointer
-# 7| 5: [Class] Program
-# 9| 5: [Field] pointer
-# 9| -1: [TypeMention] delegate* default
-# 9| 1: [AssignExpr] ... = ...
-# 9| 0: [FieldAccess] access to field pointer
-# 9| 1: [AddressOfExpr] &...
-# 9| 0: [MethodAccess] access to method M0
-# 11| 6: [Method] M0
-# 11| -1: [TypeMention] int
-# 12| 4: [BlockStmt] {...}
-# 13| 0: [ReturnStmt] return ...;
-# 13| 0: [IntLiteral] 0
-# 16| 7: [Method] M1
-# 16| -1: [TypeMention] Void
+# 3| [Class] FnPointer
+# 5| 5: [Class] Program
+# 7| 5: [Field] pointer
+# 7| -1: [TypeMention] delegate* default
+# 7| 1: [AssignExpr] ... = ...
+# 7| 0: [FieldAccess] access to field pointer
+# 7| 1: [AddressOfExpr] &...
+# 7| 0: [MethodAccess] access to method M0
+# 9| 6: [Method] M0
+# 9| -1: [TypeMention] int
+# 10| 4: [BlockStmt] {...}
+# 11| 0: [ReturnStmt] return ...;
+# 11| 0: [IntLiteral] 0
+# 14| 7: [Method] M1
+# 14| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 16| 0: [Parameter] f
-# 16| -1: [TypeMention] delegate* default
-# 17| 4: [BlockStmt] {...}
-# 18| 0: [LocalVariableDeclStmt] ... ...;
-# 18| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
-# 18| -1: [TypeMention] int
-# 18| 0: [LocalVariableAccess] access to local variable i
-# 18| 1: [IntLiteral] 42
-# 19| 1: [LocalVariableDeclStmt] ... ...;
-# 19| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
-# 19| -1: [TypeMention] int
-# 19| 0: [LocalVariableAccess] access to local variable j
-# 19| 1: [FunctionPointerCall] function pointer call
-# 19| -1: [ParameterAccess] access to parameter f
-# 19| 0: [LocalVariableAccess] access to local variable i
-# 19| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
-# 22| 8: [Method] M2
-# 22| -1: [TypeMention] Void
+# 14| 0: [Parameter] f
+# 14| -1: [TypeMention] delegate* default
+# 15| 4: [BlockStmt] {...}
+# 16| 0: [LocalVariableDeclStmt] ... ...;
+# 16| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
+# 16| -1: [TypeMention] int
+# 16| 0: [LocalVariableAccess] access to local variable i
+# 16| 1: [IntLiteral] 42
+# 17| 1: [LocalVariableDeclStmt] ... ...;
+# 17| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
+# 17| -1: [TypeMention] int
+# 17| 0: [LocalVariableAccess] access to local variable j
+# 17| 1: [FunctionPointerCall] function pointer call
+# 17| -1: [ParameterAccess] access to parameter f
+# 17| 0: [LocalVariableAccess] access to local variable i
+# 17| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
+# 20| 8: [Method] M2
+# 20| -1: [TypeMention] Void
#-----| 1: (Type parameters)
-# 22| 0: [TypeParameter] T
+# 20| 0: [TypeParameter] T
#-----| 2: (Parameters)
-# 22| 0: [Parameter] f
-# 22| -1: [TypeMention] delegate* stdcall
-# 23| 4: [BlockStmt] {...}
-# 24| 0: [LocalVariableDeclStmt] ... ...;
-# 24| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
-# 24| -1: [TypeMention] int
-# 24| 0: [LocalVariableAccess] access to local variable i
-# 24| 1: [IntLiteral] 42
-# 25| 1: [ExprStmt] ...;
-# 25| 0: [FunctionPointerCall] function pointer call
-# 25| -1: [ParameterAccess] access to parameter f
-# 25| 0: [LocalVariableAccess] access to local variable i
-# 25| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
-# 25| 2: [ObjectCreation] object creation of type T
-# 25| 0: [TypeMention] T
-# 28| 9: [Method] M3
-# 28| -1: [TypeMention] Void
+# 20| 0: [Parameter] f
+# 20| -1: [TypeMention] delegate* stdcall
+# 21| 4: [BlockStmt] {...}
+# 22| 0: [LocalVariableDeclStmt] ... ...;
+# 22| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
+# 22| -1: [TypeMention] int
+# 22| 0: [LocalVariableAccess] access to local variable i
+# 22| 1: [IntLiteral] 42
+# 23| 1: [ExprStmt] ...;
+# 23| 0: [FunctionPointerCall] function pointer call
+# 23| -1: [ParameterAccess] access to parameter f
+# 23| 0: [LocalVariableAccess] access to local variable i
+# 23| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
+# 23| 2: [ObjectCreation] object creation of type T
+# 23| 0: [TypeMention] T
+# 26| 9: [Method] M3
+# 26| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 28| 0: [Parameter] f
-# 28| -1: [TypeMention] delegate* default
-# 29| 4: [BlockStmt] {...}
-# 30| 0: [LocalVariableDeclStmt] ... ...;
-# 30| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
-# 30| -1: [TypeMention] int
-# 30| 0: [LocalVariableAccess] access to local variable i
-# 30| 1: [IntLiteral] 42
-# 31| 1: [LocalVariableDeclStmt] ... ...;
-# 31| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
-# 31| -1: [TypeMention] null
-# 31| 0: [LocalVariableAccess] access to local variable j
-# 31| 1: [RefExpr] ref ...
-# 31| 0: [FunctionPointerCall] function pointer call
-# 31| -1: [ParameterAccess] access to parameter f
-# 31| 0: [LocalVariableAccess] access to local variable i
-# 31| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
-# 31| 2: [LocalVariableAccess] access to local variable i
-# 34| 10: [Method] M4
-# 34| -1: [TypeMention] Void
+# 26| 0: [Parameter] f
+# 26| -1: [TypeMention] delegate* default
+# 27| 4: [BlockStmt] {...}
+# 28| 0: [LocalVariableDeclStmt] ... ...;
+# 28| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
+# 28| -1: [TypeMention] int
+# 28| 0: [LocalVariableAccess] access to local variable i
+# 28| 1: [IntLiteral] 42
+# 29| 1: [LocalVariableDeclStmt] ... ...;
+# 29| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
+# 29| -1: [TypeMention] null
+# 29| 0: [LocalVariableAccess] access to local variable j
+# 29| 1: [RefExpr] ref ...
+# 29| 0: [FunctionPointerCall] function pointer call
+# 29| -1: [ParameterAccess] access to parameter f
+# 29| 0: [LocalVariableAccess] access to local variable i
+# 29| 1: [LocalVariableAccess,LocalVariableDeclExpr] Object o
+# 29| 2: [LocalVariableAccess] access to local variable i
+# 32| 10: [Method] M4
+# 32| -1: [TypeMention] Void
#-----| 1: (Type parameters)
-# 34| 0: [TypeParameter] T
+# 32| 0: [TypeParameter] T
#-----| 2: (Parameters)
-# 34| 0: [Parameter] f
-# 34| -1: [TypeMention] delegate* default
-# 35| 4: [BlockStmt] {...}
-# 36| 0: [LocalVariableDeclStmt] ... ...;
-# 36| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
-# 36| -1: [TypeMention] int
-# 36| 0: [LocalVariableAccess] access to local variable j
-# 36| 1: [FunctionPointerCall] function pointer call
-# 36| -1: [ParameterAccess] access to parameter f
-# 36| 0: [ObjectCreation] object creation of type T
-# 36| 0: [TypeMention] T
-# 39| 11: [Method] M5
-# 39| -1: [TypeMention] Void
+# 32| 0: [Parameter] f
+# 32| -1: [TypeMention] delegate* default
+# 33| 4: [BlockStmt] {...}
+# 34| 0: [LocalVariableDeclStmt] ... ...;
+# 34| 0: [LocalVariableDeclAndInitExpr] Int32 j = ...
+# 34| -1: [TypeMention] int
+# 34| 0: [LocalVariableAccess] access to local variable j
+# 34| 1: [FunctionPointerCall] function pointer call
+# 34| -1: [ParameterAccess] access to parameter f
+# 34| 0: [ObjectCreation] object creation of type T
+# 34| 0: [TypeMention] T
+# 37| 11: [Method] M5
+# 37| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 39| 0: [Parameter] f
-# 39| -1: [TypeMention] delegate* default
-# 39| 1: [Parameter] ff
-# 39| -1: [TypeMention] delegate* default
-# 40| 4: [BlockStmt] {...}
-# 41| 0: [ExprStmt] ...;
-# 41| 0: [MethodCall] call to method M5
-# 41| 0: [CastExpr] (...) ...
-# 41| 1: [ParameterAccess] access to parameter ff
-# 41| 1: [ParameterAccess] access to parameter ff
-# 44| 12: [Method] M6
-# 44| -1: [TypeMention] Void
+# 37| 0: [Parameter] f
+# 37| -1: [TypeMention] delegate* default
+# 37| 1: [Parameter] ff
+# 37| -1: [TypeMention] delegate* default
+# 38| 4: [BlockStmt] {...}
+# 39| 0: [ExprStmt] ...;
+# 39| 0: [MethodCall] call to method M5
+# 39| 0: [CastExpr] (...) ...
+# 39| 1: [ParameterAccess] access to parameter ff
+# 39| 1: [ParameterAccess] access to parameter ff
+# 42| 12: [Method] M6
+# 42| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 44| 0: [Parameter] f
-# 44| -1: [TypeMention] delegate* default
-# 44| 1: [Parameter] ff
-# 44| -1: [TypeMention] delegate* default
-# 45| 4: [BlockStmt] {...}
-# 46| 0: [ExprStmt] ...;
-# 46| 0: [MethodCall] call to method M6
-# 46| 0: [CastExpr] (...) ...
-# 46| 1: [ParameterAccess] access to parameter ff
-# 46| 1: [ParameterAccess] access to parameter ff
-# 49| 13: [Class] A
-# 50| 14: [Class] B
+# 42| 0: [Parameter] f
+# 42| -1: [TypeMention] delegate* default
+# 42| 1: [Parameter] ff
+# 42| -1: [TypeMention] delegate* default
+# 43| 4: [BlockStmt] {...}
+# 44| 0: [ExprStmt] ...;
+# 44| 0: [MethodCall] call to method M6
+# 44| 0: [CastExpr] (...) ...
+# 44| 1: [ParameterAccess] access to parameter ff
+# 44| 1: [ParameterAccess] access to parameter ff
+# 47| 13: [Class] A
+# 48| 14: [Class] B
#-----| 3: (Base types)
-# 50| 0: [TypeMention] A
+# 48| 0: [TypeMention] A
GlobalStmt.cs:
-# 7| [Class] $
-# 7| 4: [Method] $
+# 5| [Class] $
+# 5| 4: [Method] $
#-----| 2: (Parameters)
# 1| 0: [Parameter] args
-# 7| 4: [BlockStmt] {...}
-# 11| 0: [ExprStmt] ...;
-# 11| 0: [MethodCall] call to method WriteLine
-# 11| -1: [TypeAccess] access to type Console
-# 11| 0: [TypeMention] Console
-# 11| 0: [StringLiteral] "1"
-# 12| 1: [ExprStmt] ...;
-# 12| 0: [MethodCall] call to method WriteLine
-# 12| -1: [TypeAccess] access to type Console
-# 12| 0: [TypeMention] Console
-# 12| 0: [StringLiteral] "2"
-# 13| 2: [ExprStmt] ...;
-# 13| 0: [LocalFunctionCall] call to local function M
-# 13| -1: [LocalFunctionAccess] access to local function M
-# 15| 3: [LocalFunctionStmt] M(...)
-# 15| 0: [LocalFunction] M
-# 16| 4: [BlockStmt] {...}
-# 19| [Class] Attr
+# 5| 4: [BlockStmt] {...}
+# 9| 0: [ExprStmt] ...;
+# 9| 0: [MethodCall] call to method WriteLine
+# 9| -1: [TypeAccess] access to type Console
+# 9| 0: [TypeMention] Console
+# 9| 0: [StringLiteral] "1"
+# 10| 1: [ExprStmt] ...;
+# 10| 0: [MethodCall] call to method WriteLine
+# 10| -1: [TypeAccess] access to type Console
+# 10| 0: [TypeMention] Console
+# 10| 0: [StringLiteral] "2"
+# 11| 2: [ExprStmt] ...;
+# 11| 0: [LocalFunctionCall] call to local function M
+# 11| -1: [LocalFunctionAccess] access to local function M
+# 13| 3: [LocalFunctionStmt] M(...)
+# 13| 0: [LocalFunction] M
+# 14| 4: [BlockStmt] {...}
+# 17| [Class] Attr
#-----| 3: (Base types)
-# 19| 0: [TypeMention] Attribute
-# 21| 5: [Method] M1
-# 21| -1: [TypeMention] Void
-# 22| 4: [BlockStmt] {...}
-# 23| 0: [ExprStmt] ...;
-# 23| 0: [MethodCall] call to method WriteLine
-# 23| -1: [TypeAccess] access to type Console
-# 23| 0: [TypeMention] Console
-# 23| 0: [StringLiteral] "3"
+# 17| 0: [TypeMention] Attribute
+# 19| 5: [Method] M1
+# 19| -1: [TypeMention] Void
+# 20| 4: [BlockStmt] {...}
+# 21| 0: [ExprStmt] ...;
+# 21| 0: [MethodCall] call to method WriteLine
+# 21| -1: [TypeAccess] access to type Console
+# 21| 0: [TypeMention] Console
+# 21| 0: [StringLiteral] "3"
InitOnlyProperty.cs:
# 3| [Class] Base
# 5| 5: [Property] Prop0
@@ -770,44 +770,44 @@ ParenthesizedPattern.cs:
# 13| 0: [VariablePatternExpr] Object p2
# 13| 3: [PropertyPatternExpr] { ... }
# 14| 1: [BlockStmt] {...}
-# 19| 6: [Method] M2
-# 19| -1: [TypeMention] Void
+# 18| 6: [Method] M2
+# 18| -1: [TypeMention] Void
#-----| 2: (Parameters)
-# 19| 0: [Parameter] o
-# 19| -1: [TypeMention] object
-# 20| 4: [BlockStmt] {...}
-# 21| 0: [LocalVariableDeclStmt] ... ...;
-# 21| 0: [LocalVariableDeclAndInitExpr] Int32 r = ...
-# 21| -1: [TypeMention] int
-# 21| 0: [LocalVariableAccess] access to local variable r
-# 21| 1: [SwitchExpr] ... switch { ... }
-# 21| -1: [ParameterAccess] access to parameter o
-# 23| 0: [SwitchCaseExpr] ... => ...
-# 23| 0: [ConstantPatternExpr,IntLiteral] 1
-# 23| 2: [IntLiteral] 1
-# 24| 1: [SwitchCaseExpr] ... => ...
-# 24| 0: [ConstantPatternExpr,IntLiteral] 2
-# 24| 2: [IntLiteral] 2
-# 25| 2: [SwitchCaseExpr] ... => ...
-# 25| 0: [VariablePatternExpr] T t
-# 25| 0: [TypeMention] T
+# 18| 0: [Parameter] o
+# 18| -1: [TypeMention] object
+# 19| 4: [BlockStmt] {...}
+# 20| 0: [LocalVariableDeclStmt] ... ...;
+# 20| 0: [LocalVariableDeclAndInitExpr] Int32 r = ...
+# 20| -1: [TypeMention] int
+# 20| 0: [LocalVariableAccess] access to local variable r
+# 20| 1: [SwitchExpr] ... switch { ... }
+# 20| -1: [ParameterAccess] access to parameter o
+# 22| 0: [SwitchCaseExpr] ... => ...
+# 22| 0: [ConstantPatternExpr,IntLiteral] 1
+# 22| 2: [IntLiteral] 1
+# 23| 1: [SwitchCaseExpr] ... => ...
+# 23| 0: [ConstantPatternExpr,IntLiteral] 2
+# 23| 2: [IntLiteral] 2
+# 24| 2: [SwitchCaseExpr] ... => ...
+# 24| 0: [VariablePatternExpr] T t
+# 24| 0: [TypeMention] T
+# 24| 1: [IsExpr] ... is ...
+# 24| 0: [LocalVariableAccess] access to local variable t
+# 24| 1: [RecursivePatternExpr] { ... }
+# 24| 3: [PropertyPatternExpr] { ... }
+# 24| 2: [IntLiteral] 3
+# 25| 3: [SwitchCaseExpr] ... => ...
+# 25| 0: [VariablePatternExpr] Object o1
+# 25| 0: [TypeMention] object
# 25| 1: [IsExpr] ... is ...
-# 25| 0: [LocalVariableAccess] access to local variable t
+# 25| 0: [LocalVariableAccess] access to local variable o1
# 25| 1: [RecursivePatternExpr] { ... }
# 25| 3: [PropertyPatternExpr] { ... }
-# 25| 2: [IntLiteral] 3
-# 26| 3: [SwitchCaseExpr] ... => ...
-# 26| 0: [VariablePatternExpr] Object o1
-# 26| 0: [TypeMention] object
-# 26| 1: [IsExpr] ... is ...
-# 26| 0: [LocalVariableAccess] access to local variable o1
-# 26| 1: [RecursivePatternExpr] { ... }
-# 26| 3: [PropertyPatternExpr] { ... }
-# 26| 2: [IntLiteral] 4
-# 27| 4: [SwitchCaseExpr] ... => ...
-# 27| 0: [TypeAccessPatternExpr] access to type String
-# 27| 0: [TypeMention] string
-# 27| 2: [IntLiteral] 5
+# 25| 2: [IntLiteral] 4
+# 26| 4: [SwitchCaseExpr] ... => ...
+# 26| 0: [TypeAccessPatternExpr] access to type String
+# 26| 0: [TypeMention] string
+# 26| 2: [IntLiteral] 5
Record.cs:
# 4| [Record] Person
# 4| 11: [NEOperator] !=
diff --git a/csharp/ql/test/library-tests/csharp9/RelationalPattern.cs b/csharp/ql/test/library-tests/csharp9/RelationalPattern.cs
index d21f5044507..3e304d740fc 100644
--- a/csharp/ql/test/library-tests/csharp9/RelationalPattern.cs
+++ b/csharp/ql/test/library-tests/csharp9/RelationalPattern.cs
@@ -20,4 +20,4 @@ public class RelationalPattern
_ => "other"
};
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/TargetType.cs b/csharp/ql/test/library-tests/csharp9/TargetType.cs
index 96a236ac3a8..2ea8d793a06 100644
--- a/csharp/ql/test/library-tests/csharp9/TargetType.cs
+++ b/csharp/ql/test/library-tests/csharp9/TargetType.cs
@@ -38,4 +38,4 @@ public class TargetType
}
public static implicit operator int(TargetType d) => 0;
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/TypeParameterNullability.cs b/csharp/ql/test/library-tests/csharp9/TypeParameterNullability.cs
index 8b45ee32d26..b3613930bf5 100644
--- a/csharp/ql/test/library-tests/csharp9/TypeParameterNullability.cs
+++ b/csharp/ql/test/library-tests/csharp9/TypeParameterNullability.cs
@@ -22,4 +22,4 @@ class B2 : A2
class B3 : A2
{
public override void F2(T? t) where T: struct { } // value type
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/TypePattern.cs b/csharp/ql/test/library-tests/csharp9/TypePattern.cs
index 100a95f9e7d..cee23e125d2 100644
--- a/csharp/ql/test/library-tests/csharp9/TypePattern.cs
+++ b/csharp/ql/test/library-tests/csharp9/TypePattern.cs
@@ -14,4 +14,4 @@ public class TypePattern
System.Object o => o
};
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/UnaryPattern.cs b/csharp/ql/test/library-tests/csharp9/UnaryPattern.cs
index 5dfcb335bfb..600f8bd311d 100644
--- a/csharp/ql/test/library-tests/csharp9/UnaryPattern.cs
+++ b/csharp/ql/test/library-tests/csharp9/UnaryPattern.cs
@@ -19,4 +19,4 @@ public class UnaryPattern
_ => "other"
};
}
-}
\ No newline at end of file
+}
diff --git a/csharp/ql/test/library-tests/csharp9/foreach.expected b/csharp/ql/test/library-tests/csharp9/foreach.expected
index 39694665cb0..551729436d3 100644
--- a/csharp/ql/test/library-tests/csharp9/foreach.expected
+++ b/csharp/ql/test/library-tests/csharp9/foreach.expected
@@ -1,4 +1,4 @@
-| ForeachExtension.cs:24:9:26:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:8:34:8:49 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - |
-| ForeachExtension.cs:29:9:31:9 | foreach (... ... in ...) ... | Int32 | async | Extensions | ForeachExtension.cs:9:39:9:59 | System.Collections.Generic.IAsyncEnumerator | - | System.Collections.Generic.IAsyncEnumerator | - |
-| ForeachExtension.cs:33:9:35:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:10:36:10:48 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - |
+| ForeachExtension.cs:24:9:26:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:8:34:8:49 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - |
+| ForeachExtension.cs:29:9:31:9 | foreach (... ... in ...) ... | Int32 | async | Extensions | ForeachExtension.cs:9:39:9:59 | System.Collections.Generic.IAsyncEnumerator | - | System.Collections.Generic.IAsyncEnumerator | - |
+| ForeachExtension.cs:33:9:35:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:10:36:10:48 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - |
| ForeachExtension.cs:37:9:39:9 | foreach (... ... in ...) ... | Int32 | sync | System.Collections.IEnumerable | - | System.Collections.IEnumerator | - | System.Collections.IEnumerator | - |
diff --git a/csharp/ql/test/library-tests/csharp9/globalStmt.expected b/csharp/ql/test/library-tests/csharp9/globalStmt.expected
index dc7ccea6ad1..f16742b4aa9 100644
--- a/csharp/ql/test/library-tests/csharp9/globalStmt.expected
+++ b/csharp/ql/test/library-tests/csharp9/globalStmt.expected
@@ -1,10 +1,10 @@
global_stmt
-| GlobalStmt.cs:11:1:11:23 | ...; |
-| GlobalStmt.cs:12:1:12:23 | ...; |
-| GlobalStmt.cs:13:1:13:4 | ...; |
-| GlobalStmt.cs:15:1:17:1 | M(...) |
+| GlobalStmt.cs:9:1:9:23 | ...; |
+| GlobalStmt.cs:10:1:10:23 | ...; |
+| GlobalStmt.cs:11:1:11:4 | ...; |
+| GlobalStmt.cs:13:1:15:1 | M(...) |
globalBlock
-| GlobalStmt.cs:7:1:25:1 | {...} | GlobalStmt.cs:7:1:25:1 | $ | GlobalStmt.cs:1:1:1:0 | args | GlobalStmt.cs:7:1:25:1 | $ |
+| GlobalStmt.cs:5:1:24:0 | {...} | GlobalStmt.cs:5:1:24:0 | $ | GlobalStmt.cs:1:1:1:0 | args | GlobalStmt.cs:5:1:24:0 | $ |
methods
-| GlobalStmt.cs:7:1:25:1 | $ | entry |
-| GlobalStmt.cs:21:8:21:9 | M1 | non-entry |
+| GlobalStmt.cs:5:1:24:0 | $ | entry |
+| GlobalStmt.cs:19:8:19:9 | M1 | non-entry |
diff --git a/csharp/ql/test/library-tests/csharp9/options b/csharp/ql/test/library-tests/csharp9/options
new file mode 100644
index 00000000000..7ba3811b2af
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp9/options
@@ -0,0 +1 @@
+semmle-extractor-options: --standalone
diff --git a/csharp/ql/test/library-tests/csharp9/typePattern.expected b/csharp/ql/test/library-tests/csharp9/typePattern.expected
index 158d7050af4..7c85333e1c1 100644
--- a/csharp/ql/test/library-tests/csharp9/typePattern.expected
+++ b/csharp/ql/test/library-tests/csharp9/typePattern.expected
@@ -5,9 +5,9 @@
| BinaryPattern.cs:12:27:12:41 | BinaryPattern u | BinaryPattern |
| ParenthesizedPattern.cs:9:18:9:22 | Object p1 | Object |
| ParenthesizedPattern.cs:13:19:13:23 | Object p2 | Object |
-| ParenthesizedPattern.cs:25:13:25:15 | T t | T |
-| ParenthesizedPattern.cs:26:14:26:22 | Object o1 | Object |
-| ParenthesizedPattern.cs:27:14:27:19 | access to type String | String |
+| ParenthesizedPattern.cs:24:13:24:15 | T t | T |
+| ParenthesizedPattern.cs:25:14:25:22 | Object o1 | Object |
+| ParenthesizedPattern.cs:26:14:26:19 | access to type String | String |
| TypePattern.cs:8:19:8:21 | access to type Int32 | Int32 |
| TypePattern.cs:8:24:8:29 | access to type String | String |
| TypePattern.cs:11:13:11:15 | access to type Int32 | Int32 |
diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs
index 948d0498983..a4ee5b7d6da 100644
--- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs
+++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs
@@ -129,7 +129,6 @@ public class A
}
}
-
public void CallSinkIfFalse(object o, bool cond)
{
if (!cond)
@@ -138,7 +137,6 @@ public class A
}
}
-
public void LocalCallSensitivity(object o, bool c)
{
object o1 = o;
diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected
index 170ceccf5c4..6afa5f20756 100644
--- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected
+++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected
@@ -23,17 +23,17 @@ edges
| CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object : Object | CallSensitivityFlow.cs:43:45:43:45 | o : Object |
| CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object : Object | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough |
| CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:124:43:124:43 | o : Object |
-| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:133:44:133:44 | o : Object |
-| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:142:49:142:49 | o : Object |
+| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:132:44:132:44 | o : Object |
+| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:140:49:140:49 | o : Object |
| CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o |
-| CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o |
-| CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 |
-| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o |
-| CallSensitivityFlow.cs:169:44:169:44 | o : Object | CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object |
-| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object |
-| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:197:40:197:40 | o : Object |
-| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:169:44:169:44 | o : Object |
-| CallSensitivityFlow.cs:197:40:197:40 | o : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o |
+| CallSensitivityFlow.cs:132:44:132:44 | o : Object | CallSensitivityFlow.cs:136:22:136:22 | access to parameter o |
+| CallSensitivityFlow.cs:140:49:140:49 | o : Object | CallSensitivityFlow.cs:150:18:150:19 | access to local variable o3 |
+| CallSensitivityFlow.cs:162:34:162:34 | o : Object | CallSensitivityFlow.cs:164:14:164:14 | access to parameter o |
+| CallSensitivityFlow.cs:167:44:167:44 | o : Object | CallSensitivityFlow.cs:169:14:169:14 | access to parameter o : Object |
+| CallSensitivityFlow.cs:169:14:169:14 | access to parameter o : Object | CallSensitivityFlow.cs:162:34:162:34 | o : Object |
+| CallSensitivityFlow.cs:178:21:178:32 | object creation of type Object : Object | CallSensitivityFlow.cs:195:40:195:40 | o : Object |
+| CallSensitivityFlow.cs:181:21:181:32 | object creation of type Object : Object | CallSensitivityFlow.cs:167:44:167:44 | o : Object |
+| CallSensitivityFlow.cs:195:40:195:40 | o : Object | CallSensitivityFlow.cs:198:18:198:18 | access to parameter o |
nodes
| CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object |
| CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o |
@@ -70,18 +70,18 @@ nodes
| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
| CallSensitivityFlow.cs:124:43:124:43 | o : Object | semmle.label | o : Object |
| CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | semmle.label | access to parameter o |
-| CallSensitivityFlow.cs:133:44:133:44 | o : Object | semmle.label | o : Object |
-| CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o |
-| CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object |
-| CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 |
-| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object |
-| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o |
-| CallSensitivityFlow.cs:169:44:169:44 | o : Object | semmle.label | o : Object |
-| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | semmle.label | access to parameter o : Object |
-| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
-| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
-| CallSensitivityFlow.cs:197:40:197:40 | o : Object | semmle.label | o : Object |
-| CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | semmle.label | access to parameter o |
+| CallSensitivityFlow.cs:132:44:132:44 | o : Object | semmle.label | o : Object |
+| CallSensitivityFlow.cs:136:22:136:22 | access to parameter o | semmle.label | access to parameter o |
+| CallSensitivityFlow.cs:140:49:140:49 | o : Object | semmle.label | o : Object |
+| CallSensitivityFlow.cs:150:18:150:19 | access to local variable o3 | semmle.label | access to local variable o3 |
+| CallSensitivityFlow.cs:162:34:162:34 | o : Object | semmle.label | o : Object |
+| CallSensitivityFlow.cs:164:14:164:14 | access to parameter o | semmle.label | access to parameter o |
+| CallSensitivityFlow.cs:167:44:167:44 | o : Object | semmle.label | o : Object |
+| CallSensitivityFlow.cs:169:14:169:14 | access to parameter o : Object | semmle.label | access to parameter o : Object |
+| CallSensitivityFlow.cs:178:21:178:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
+| CallSensitivityFlow.cs:181:21:181:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
+| CallSensitivityFlow.cs:195:40:195:40 | o : Object | semmle.label | o : Object |
+| CallSensitivityFlow.cs:198:18:198:18 | access to parameter o | semmle.label | access to parameter o |
#select
| CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o |
@@ -98,7 +98,7 @@ nodes
| CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object : Object | CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object : Object | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object : Object | CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object : Object | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough | $@ | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough | call to method FlowThrough |
| CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o |
-| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o |
-| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 |
-| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | $@ | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | access to parameter o |
-| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o |
+| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:136:22:136:22 | access to parameter o | $@ | CallSensitivityFlow.cs:136:22:136:22 | access to parameter o | access to parameter o |
+| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:150:18:150:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:150:18:150:19 | access to local variable o3 | access to local variable o3 |
+| CallSensitivityFlow.cs:178:21:178:32 | object creation of type Object : Object | CallSensitivityFlow.cs:178:21:178:32 | object creation of type Object : Object | CallSensitivityFlow.cs:198:18:198:18 | access to parameter o | $@ | CallSensitivityFlow.cs:198:18:198:18 | access to parameter o | access to parameter o |
+| CallSensitivityFlow.cs:181:21:181:32 | object creation of type Object : Object | CallSensitivityFlow.cs:181:21:181:32 | object creation of type Object : Object | CallSensitivityFlow.cs:164:14:164:14 | access to parameter o | $@ | CallSensitivityFlow.cs:164:14:164:14 | access to parameter o | access to parameter o |
diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs
index 5f1bf2a6731..a7bb6130bb1 100644
--- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs
+++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs
@@ -1,4 +1,3 @@
-// semmle-extractor-options: /r:System.Linq.dll
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected
index 3295c03ac94..3d085a640a3 100644
--- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected
+++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected
@@ -1,421 +1,421 @@
edges
-| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:15:27:15:27 | access to local variable a : A |
-| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A |
-| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A |
-| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A |
-| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A |
-| CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A | CollectionFlow.cs:16:14:16:19 | access to array element |
-| CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A |
-| CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A | CollectionFlow.cs:18:14:18:23 | call to method First |
-| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:33:53:33:53 | access to local variable a : A |
-| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A |
-| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A |
-| CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A | CollectionFlow.cs:34:14:34:17 | access to field As [element] : A |
-| CollectionFlow.cs:34:14:34:17 | access to field As [element] : A | CollectionFlow.cs:34:14:34:20 | access to array element |
-| CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A | CollectionFlow.cs:35:18:35:21 | access to field As [element] : A |
-| CollectionFlow.cs:35:18:35:21 | access to field As [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A |
-| CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A | CollectionFlow.cs:36:20:36:23 | access to field As [element] : A |
-| CollectionFlow.cs:36:20:36:23 | access to field As [element] : A | CollectionFlow.cs:36:14:36:24 | call to method First |
-| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:52:18:52:18 | access to local variable a : A |
-| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A |
-| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A |
-| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A |
-| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A |
-| CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A | CollectionFlow.cs:53:14:53:19 | access to array element |
-| CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A |
-| CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A | CollectionFlow.cs:55:14:55:23 | call to method First |
-| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:72:19:72:19 | access to local variable a : A |
-| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A |
-| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A |
-| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A |
-| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A | CollectionFlow.cs:73:14:73:20 | access to indexer |
-| CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A |
-| CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst |
-| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:90:36:90:36 | access to local variable a : A |
-| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A |
-| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A |
-| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A |
-| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A |
-| CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | CollectionFlow.cs:91:14:91:20 | access to indexer |
-| CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A |
-| CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst |
-| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:108:18:108:18 | access to local variable a : A |
-| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A |
-| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A |
-| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A |
-| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A | CollectionFlow.cs:109:14:109:20 | access to indexer |
-| CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A |
-| CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst |
-| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:19:127:19 | access to local variable a : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:128:14:128:20 | access to indexer |
-| CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A |
-| CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero |
-| CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue |
-| CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst |
-| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:52:149:52 | access to local variable a : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A |
-| CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:150:14:150:20 | access to indexer |
-| CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A |
-| CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero |
-| CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue |
-| CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst |
-| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:53:170:53 | access to local variable a : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A |
-| CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:171:14:171:20 | access to indexer |
-| CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A |
-| CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero |
-| CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue |
-| CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst |
-| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:49:192:49 | access to local variable a : A |
-| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A |
-| CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A |
-| CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | CollectionFlow.cs:193:14:193:30 | call to method First |
-| CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A |
-| CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst |
-| CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey |
-| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:48:211:48 | access to local variable a : A |
-| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A |
-| CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A |
-| CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | CollectionFlow.cs:212:14:212:30 | call to method First |
-| CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A |
-| CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst |
-| CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey |
-| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:230:27:230:27 | access to local variable a : A |
-| CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A | CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A |
-| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A |
-| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | CollectionFlow.cs:232:18:232:18 | access to local variable x |
-| CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A |
-| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:245:27:245:27 | access to local variable a : A |
-| CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A | CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A |
-| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A |
-| CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A | CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A |
-| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A |
-| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:248:18:248:35 | access to property Current |
-| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:263:18:263:18 | access to local variable a : A |
-| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A |
-| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A | CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A |
-| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A |
-| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:266:18:266:35 | access to property Current |
-| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:282:43:282:43 | access to local variable a : A |
-| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A | CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A |
-| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A |
-| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A |
-| CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A | CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A |
-| CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A | CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A |
-| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A | CollectionFlow.cs:285:18:285:24 | access to property Key |
-| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:308:23:308:23 | access to local variable a : A |
-| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A |
-| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A |
-| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A |
-| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A |
-| CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A | CollectionFlow.cs:309:14:309:19 | access to array element |
-| CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A |
-| CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A | CollectionFlow.cs:311:14:311:23 | call to method First |
-| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:330:23:330:23 | access to local variable a : A |
-| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A |
-| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A |
-| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A |
-| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A | CollectionFlow.cs:331:14:331:20 | access to indexer |
-| CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A |
-| CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst |
-| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A |
-| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A |
-| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A |
-| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [element] : A | CollectionFlow.cs:396:49:396:52 | args [element] : A |
-| CollectionFlow.cs:350:28:350:38 | { ..., ... } [element] : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] [element] : A |
-| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:28:350:38 | { ..., ... } [element] : A |
-| CollectionFlow.cs:374:40:374:41 | ts [element] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A |
-| CollectionFlow.cs:374:40:374:41 | ts [element] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A |
-| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | CollectionFlow.cs:374:52:374:56 | access to array element |
-| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | CollectionFlow.cs:374:52:374:56 | access to array element |
-| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A |
-| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A |
-| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A |
-| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A |
-| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer |
-| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer |
-| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer |
-| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer |
-| CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | CollectionFlow.cs:378:75:378:78 | access to parameter dict [element, property Value] : A |
-| CollectionFlow.cs:378:75:378:78 | access to parameter dict [element, property Value] : A | CollectionFlow.cs:378:75:378:81 | access to indexer |
-| CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | CollectionFlow.cs:380:73:380:76 | access to parameter dict [element, property Key] : A |
-| CollectionFlow.cs:380:73:380:76 | access to parameter dict [element, property Key] : A | CollectionFlow.cs:380:73:380:81 | access to property Keys [element] : A |
-| CollectionFlow.cs:380:73:380:81 | access to property Keys [element] : A | CollectionFlow.cs:380:73:380:89 | call to method First |
-| CollectionFlow.cs:396:49:396:52 | args [element] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A |
-| CollectionFlow.cs:396:49:396:52 | args [element] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A |
-| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | CollectionFlow.cs:396:63:396:69 | access to array element |
-| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | CollectionFlow.cs:396:63:396:69 | access to array element |
+| CollectionFlow.cs:13:17:13:23 | object creation of type A : A | CollectionFlow.cs:14:27:14:27 | access to local variable a : A |
+| CollectionFlow.cs:14:25:14:29 | { ..., ... } [element] : A | CollectionFlow.cs:15:14:15:16 | access to local variable as [element] : A |
+| CollectionFlow.cs:14:25:14:29 | { ..., ... } [element] : A | CollectionFlow.cs:16:18:16:20 | access to local variable as [element] : A |
+| CollectionFlow.cs:14:25:14:29 | { ..., ... } [element] : A | CollectionFlow.cs:17:20:17:22 | access to local variable as [element] : A |
+| CollectionFlow.cs:14:27:14:27 | access to local variable a : A | CollectionFlow.cs:14:25:14:29 | { ..., ... } [element] : A |
+| CollectionFlow.cs:15:14:15:16 | access to local variable as [element] : A | CollectionFlow.cs:15:14:15:19 | access to array element |
+| CollectionFlow.cs:16:18:16:20 | access to local variable as [element] : A | CollectionFlow.cs:373:40:373:41 | ts [element] : A |
+| CollectionFlow.cs:17:20:17:22 | access to local variable as [element] : A | CollectionFlow.cs:17:14:17:23 | call to method First |
+| CollectionFlow.cs:31:17:31:23 | object creation of type A : A | CollectionFlow.cs:32:53:32:53 | access to local variable a : A |
+| CollectionFlow.cs:32:38:32:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:33:14:33:14 | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:32:38:32:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:34:18:34:18 | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:32:38:32:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:35:20:35:20 | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:32:45:32:55 | { ..., ... } [element] : A | CollectionFlow.cs:32:38:32:57 | { ..., ... } [field As, element] : A |
+| CollectionFlow.cs:32:53:32:53 | access to local variable a : A | CollectionFlow.cs:32:45:32:55 | { ..., ... } [element] : A |
+| CollectionFlow.cs:33:14:33:14 | access to local variable c [field As, element] : A | CollectionFlow.cs:33:14:33:17 | access to field As [element] : A |
+| CollectionFlow.cs:33:14:33:17 | access to field As [element] : A | CollectionFlow.cs:33:14:33:20 | access to array element |
+| CollectionFlow.cs:34:18:34:18 | access to local variable c [field As, element] : A | CollectionFlow.cs:34:18:34:21 | access to field As [element] : A |
+| CollectionFlow.cs:34:18:34:21 | access to field As [element] : A | CollectionFlow.cs:373:40:373:41 | ts [element] : A |
+| CollectionFlow.cs:35:20:35:20 | access to local variable c [field As, element] : A | CollectionFlow.cs:35:20:35:23 | access to field As [element] : A |
+| CollectionFlow.cs:35:20:35:23 | access to field As [element] : A | CollectionFlow.cs:35:14:35:24 | call to method First |
+| CollectionFlow.cs:49:17:49:23 | object creation of type A : A | CollectionFlow.cs:51:18:51:18 | access to local variable a : A |
+| CollectionFlow.cs:51:9:51:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:52:14:52:16 | access to local variable as [element] : A |
+| CollectionFlow.cs:51:9:51:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:53:18:53:20 | access to local variable as [element] : A |
+| CollectionFlow.cs:51:9:51:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:54:20:54:22 | access to local variable as [element] : A |
+| CollectionFlow.cs:51:18:51:18 | access to local variable a : A | CollectionFlow.cs:51:9:51:11 | [post] access to local variable as [element] : A |
+| CollectionFlow.cs:52:14:52:16 | access to local variable as [element] : A | CollectionFlow.cs:52:14:52:19 | access to array element |
+| CollectionFlow.cs:53:18:53:20 | access to local variable as [element] : A | CollectionFlow.cs:373:40:373:41 | ts [element] : A |
+| CollectionFlow.cs:54:20:54:22 | access to local variable as [element] : A | CollectionFlow.cs:54:14:54:23 | call to method First |
+| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:19:71:19 | access to local variable a : A |
+| CollectionFlow.cs:71:9:71:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:72:14:72:17 | access to local variable list [element] : A |
+| CollectionFlow.cs:71:9:71:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:73:22:73:25 | access to local variable list [element] : A |
+| CollectionFlow.cs:71:9:71:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:74:24:74:27 | access to local variable list [element] : A |
+| CollectionFlow.cs:71:19:71:19 | access to local variable a : A | CollectionFlow.cs:71:9:71:12 | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:72:14:72:17 | access to local variable list [element] : A | CollectionFlow.cs:72:14:72:20 | access to indexer |
+| CollectionFlow.cs:73:22:73:25 | access to local variable list [element] : A | CollectionFlow.cs:375:49:375:52 | list [element] : A |
+| CollectionFlow.cs:74:24:74:27 | access to local variable list [element] : A | CollectionFlow.cs:74:14:74:28 | call to method ListFirst |
+| CollectionFlow.cs:88:17:88:23 | object creation of type A : A | CollectionFlow.cs:89:36:89:36 | access to local variable a : A |
+| CollectionFlow.cs:89:20:89:38 | object creation of type List [element] : A | CollectionFlow.cs:90:14:90:17 | access to local variable list [element] : A |
+| CollectionFlow.cs:89:20:89:38 | object creation of type List [element] : A | CollectionFlow.cs:91:22:91:25 | access to local variable list [element] : A |
+| CollectionFlow.cs:89:20:89:38 | object creation of type List [element] : A | CollectionFlow.cs:92:24:92:27 | access to local variable list [element] : A |
+| CollectionFlow.cs:89:36:89:36 | access to local variable a : A | CollectionFlow.cs:89:20:89:38 | object creation of type List [element] : A |
+| CollectionFlow.cs:90:14:90:17 | access to local variable list [element] : A | CollectionFlow.cs:90:14:90:20 | access to indexer |
+| CollectionFlow.cs:91:22:91:25 | access to local variable list [element] : A | CollectionFlow.cs:375:49:375:52 | list [element] : A |
+| CollectionFlow.cs:92:24:92:27 | access to local variable list [element] : A | CollectionFlow.cs:92:14:92:28 | call to method ListFirst |
+| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:107:18:107:18 | access to local variable a : A |
+| CollectionFlow.cs:107:9:107:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:108:14:108:17 | access to local variable list [element] : A |
+| CollectionFlow.cs:107:9:107:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:109:22:109:25 | access to local variable list [element] : A |
+| CollectionFlow.cs:107:9:107:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:110:24:110:27 | access to local variable list [element] : A |
+| CollectionFlow.cs:107:18:107:18 | access to local variable a : A | CollectionFlow.cs:107:9:107:12 | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:108:14:108:17 | access to local variable list [element] : A | CollectionFlow.cs:108:14:108:20 | access to indexer |
+| CollectionFlow.cs:109:22:109:25 | access to local variable list [element] : A | CollectionFlow.cs:375:49:375:52 | list [element] : A |
+| CollectionFlow.cs:110:24:110:27 | access to local variable list [element] : A | CollectionFlow.cs:110:14:110:28 | call to method ListFirst |
+| CollectionFlow.cs:124:17:124:23 | object creation of type A : A | CollectionFlow.cs:126:19:126:19 | access to local variable a : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:127:14:127:17 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:128:23:128:26 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:129:28:129:31 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:29:130:32 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:30:131:33 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:19:126:19 | access to local variable a : A | CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:127:14:127:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:127:14:127:20 | access to indexer |
+| CollectionFlow.cs:128:23:128:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A |
+| CollectionFlow.cs:129:28:129:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:129:14:129:32 | call to method DictIndexZero |
+| CollectionFlow.cs:130:29:130:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:14:130:33 | call to method DictFirstValue |
+| CollectionFlow.cs:131:30:131:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:14:131:34 | call to method DictValuesFirst |
+| CollectionFlow.cs:147:17:147:23 | object creation of type A : A | CollectionFlow.cs:148:52:148:52 | access to local variable a : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:149:14:149:17 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:150:23:150:26 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:151:28:151:31 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:152:29:152:32 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:153:30:153:33 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:148:52:148:52 | access to local variable a : A | CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A |
+| CollectionFlow.cs:149:14:149:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:149:14:149:20 | access to indexer |
+| CollectionFlow.cs:150:23:150:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A |
+| CollectionFlow.cs:151:28:151:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:151:14:151:32 | call to method DictIndexZero |
+| CollectionFlow.cs:152:29:152:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:152:14:152:33 | call to method DictFirstValue |
+| CollectionFlow.cs:153:30:153:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:153:14:153:34 | call to method DictValuesFirst |
+| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:169:53:169:53 | access to local variable a : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:170:14:170:17 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:171:23:171:26 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:172:28:172:31 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:173:29:173:32 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:174:30:174:33 | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:169:53:169:53 | access to local variable a : A | CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary [element, property Value] : A |
+| CollectionFlow.cs:170:14:170:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:170:14:170:20 | access to indexer |
+| CollectionFlow.cs:171:23:171:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A |
+| CollectionFlow.cs:172:28:172:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:172:14:172:32 | call to method DictIndexZero |
+| CollectionFlow.cs:173:29:173:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:173:14:173:33 | call to method DictFirstValue |
+| CollectionFlow.cs:174:30:174:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:174:14:174:34 | call to method DictValuesFirst |
+| CollectionFlow.cs:190:17:190:23 | object creation of type A : A | CollectionFlow.cs:191:49:191:49 | access to local variable a : A |
+| CollectionFlow.cs:191:20:191:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:192:14:192:17 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:191:20:191:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:193:21:193:24 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:191:20:191:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:194:28:194:31 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:191:20:191:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:195:27:195:30 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:191:49:191:49 | access to local variable a : A | CollectionFlow.cs:191:20:191:56 | object creation of type Dictionary [element, property Key] : A |
+| CollectionFlow.cs:192:14:192:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:192:14:192:22 | access to property Keys [element] : A |
+| CollectionFlow.cs:192:14:192:22 | access to property Keys [element] : A | CollectionFlow.cs:192:14:192:30 | call to method First |
+| CollectionFlow.cs:193:21:193:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:379:59:379:62 | dict [element, property Key] : A |
+| CollectionFlow.cs:194:28:194:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:194:14:194:32 | call to method DictKeysFirst |
+| CollectionFlow.cs:195:27:195:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:195:14:195:31 | call to method DictFirstKey |
+| CollectionFlow.cs:209:17:209:23 | object creation of type A : A | CollectionFlow.cs:210:48:210:48 | access to local variable a : A |
+| CollectionFlow.cs:210:20:210:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:211:14:211:17 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:210:20:210:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:212:21:212:24 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:210:20:210:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:213:28:213:31 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:210:20:210:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:214:27:214:30 | access to local variable dict [element, property Key] : A |
+| CollectionFlow.cs:210:48:210:48 | access to local variable a : A | CollectionFlow.cs:210:20:210:55 | object creation of type Dictionary [element, property Key] : A |
+| CollectionFlow.cs:211:14:211:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:211:14:211:22 | access to property Keys [element] : A |
+| CollectionFlow.cs:211:14:211:22 | access to property Keys [element] : A | CollectionFlow.cs:211:14:211:30 | call to method First |
+| CollectionFlow.cs:212:21:212:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:379:59:379:62 | dict [element, property Key] : A |
+| CollectionFlow.cs:213:28:213:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:213:14:213:32 | call to method DictKeysFirst |
+| CollectionFlow.cs:214:27:214:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:214:14:214:31 | call to method DictFirstKey |
+| CollectionFlow.cs:228:17:228:23 | object creation of type A : A | CollectionFlow.cs:229:27:229:27 | access to local variable a : A |
+| CollectionFlow.cs:229:25:229:29 | { ..., ... } [element] : A | CollectionFlow.cs:230:27:230:29 | access to local variable as [element] : A |
+| CollectionFlow.cs:229:27:229:27 | access to local variable a : A | CollectionFlow.cs:229:25:229:29 | { ..., ... } [element] : A |
+| CollectionFlow.cs:230:22:230:22 | SSA def(x) : A | CollectionFlow.cs:231:18:231:18 | access to local variable x |
+| CollectionFlow.cs:230:27:230:29 | access to local variable as [element] : A | CollectionFlow.cs:230:22:230:22 | SSA def(x) : A |
+| CollectionFlow.cs:243:17:243:23 | object creation of type A : A | CollectionFlow.cs:244:27:244:27 | access to local variable a : A |
+| CollectionFlow.cs:244:25:244:29 | { ..., ... } [element] : A | CollectionFlow.cs:245:26:245:28 | access to local variable as [element] : A |
+| CollectionFlow.cs:244:27:244:27 | access to local variable a : A | CollectionFlow.cs:244:25:244:29 | { ..., ... } [element] : A |
+| CollectionFlow.cs:245:26:245:28 | access to local variable as [element] : A | CollectionFlow.cs:245:26:245:44 | call to method GetEnumerator [property Current] : A |
+| CollectionFlow.cs:245:26:245:44 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:247:18:247:27 | access to local variable enumerator [property Current] : A |
+| CollectionFlow.cs:247:18:247:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:247:18:247:35 | access to property Current |
+| CollectionFlow.cs:260:17:260:23 | object creation of type A : A | CollectionFlow.cs:262:18:262:18 | access to local variable a : A |
+| CollectionFlow.cs:262:9:262:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:263:26:263:29 | access to local variable list [element] : A |
+| CollectionFlow.cs:262:18:262:18 | access to local variable a : A | CollectionFlow.cs:262:9:262:12 | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:263:26:263:29 | access to local variable list [element] : A | CollectionFlow.cs:263:26:263:45 | call to method GetEnumerator [property Current] : A |
+| CollectionFlow.cs:263:26:263:45 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:265:18:265:27 | access to local variable enumerator [property Current] : A |
+| CollectionFlow.cs:265:18:265:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:265:18:265:35 | access to property Current |
+| CollectionFlow.cs:279:17:279:23 | object creation of type A : A | CollectionFlow.cs:281:43:281:43 | access to local variable a : A |
+| CollectionFlow.cs:281:9:281:12 | [post] access to local variable list [element, property Key] : A | CollectionFlow.cs:282:9:282:12 | access to local variable list [element, property Key] : A |
+| CollectionFlow.cs:281:18:281:47 | object creation of type KeyValuePair [property Key] : A | CollectionFlow.cs:281:9:281:12 | [post] access to local variable list [element, property Key] : A |
+| CollectionFlow.cs:281:43:281:43 | access to local variable a : A | CollectionFlow.cs:281:18:281:47 | object creation of type KeyValuePair [property Key] : A |
+| CollectionFlow.cs:282:9:282:12 | access to local variable list [element, property Key] : A | CollectionFlow.cs:282:21:282:23 | kvp [property Key] : A |
+| CollectionFlow.cs:282:21:282:23 | kvp [property Key] : A | CollectionFlow.cs:284:18:284:20 | access to parameter kvp [property Key] : A |
+| CollectionFlow.cs:284:18:284:20 | access to parameter kvp [property Key] : A | CollectionFlow.cs:284:18:284:24 | access to property Key |
+| CollectionFlow.cs:305:17:305:23 | object creation of type A : A | CollectionFlow.cs:307:23:307:23 | access to local variable a : A |
+| CollectionFlow.cs:307:18:307:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:308:14:308:16 | access to local variable as [element] : A |
+| CollectionFlow.cs:307:18:307:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:309:18:309:20 | access to local variable as [element] : A |
+| CollectionFlow.cs:307:18:307:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:310:20:310:22 | access to local variable as [element] : A |
+| CollectionFlow.cs:307:23:307:23 | access to local variable a : A | CollectionFlow.cs:307:18:307:20 | [post] access to local variable as [element] : A |
+| CollectionFlow.cs:308:14:308:16 | access to local variable as [element] : A | CollectionFlow.cs:308:14:308:19 | access to array element |
+| CollectionFlow.cs:309:18:309:20 | access to local variable as [element] : A | CollectionFlow.cs:373:40:373:41 | ts [element] : A |
+| CollectionFlow.cs:310:20:310:22 | access to local variable as [element] : A | CollectionFlow.cs:310:14:310:23 | call to method First |
+| CollectionFlow.cs:327:17:327:23 | object creation of type A : A | CollectionFlow.cs:329:23:329:23 | access to local variable a : A |
+| CollectionFlow.cs:329:17:329:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:330:14:330:17 | access to local variable list [element] : A |
+| CollectionFlow.cs:329:17:329:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:331:22:331:25 | access to local variable list [element] : A |
+| CollectionFlow.cs:329:17:329:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:332:24:332:27 | access to local variable list [element] : A |
+| CollectionFlow.cs:329:23:329:23 | access to local variable a : A | CollectionFlow.cs:329:17:329:20 | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:330:14:330:17 | access to local variable list [element] : A | CollectionFlow.cs:330:14:330:20 | access to indexer |
+| CollectionFlow.cs:331:22:331:25 | access to local variable list [element] : A | CollectionFlow.cs:375:49:375:52 | list [element] : A |
+| CollectionFlow.cs:332:24:332:27 | access to local variable list [element] : A | CollectionFlow.cs:332:14:332:28 | call to method ListFirst |
+| CollectionFlow.cs:346:20:346:26 | object creation of type A : A | CollectionFlow.cs:395:49:395:52 | args [element] : A |
+| CollectionFlow.cs:347:26:347:32 | object creation of type A : A | CollectionFlow.cs:395:49:395:52 | args [element] : A |
+| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:395:49:395:52 | args [element] : A |
+| CollectionFlow.cs:349:20:349:38 | array creation of type A[] [element] : A | CollectionFlow.cs:395:49:395:52 | args [element] : A |
+| CollectionFlow.cs:349:28:349:38 | { ..., ... } [element] : A | CollectionFlow.cs:349:20:349:38 | array creation of type A[] [element] : A |
+| CollectionFlow.cs:349:30:349:36 | object creation of type A : A | CollectionFlow.cs:349:28:349:38 | { ..., ... } [element] : A |
+| CollectionFlow.cs:373:40:373:41 | ts [element] : A | CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A |
+| CollectionFlow.cs:373:40:373:41 | ts [element] : A | CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A |
+| CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A | CollectionFlow.cs:373:52:373:56 | access to array element |
+| CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A | CollectionFlow.cs:373:52:373:56 | access to array element |
+| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
+| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
+| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
+| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
+| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
+| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
+| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
+| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
+| CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A | CollectionFlow.cs:377:75:377:78 | access to parameter dict [element, property Value] : A |
+| CollectionFlow.cs:377:75:377:78 | access to parameter dict [element, property Value] : A | CollectionFlow.cs:377:75:377:81 | access to indexer |
+| CollectionFlow.cs:379:59:379:62 | dict [element, property Key] : A | CollectionFlow.cs:379:73:379:76 | access to parameter dict [element, property Key] : A |
+| CollectionFlow.cs:379:73:379:76 | access to parameter dict [element, property Key] : A | CollectionFlow.cs:379:73:379:81 | access to property Keys [element] : A |
+| CollectionFlow.cs:379:73:379:81 | access to property Keys [element] : A | CollectionFlow.cs:379:73:379:89 | call to method First |
+| CollectionFlow.cs:395:49:395:52 | args [element] : A | CollectionFlow.cs:395:63:395:66 | access to parameter args [element] : A |
+| CollectionFlow.cs:395:49:395:52 | args [element] : A | CollectionFlow.cs:395:63:395:66 | access to parameter args [element] : A |
+| CollectionFlow.cs:395:63:395:66 | access to parameter args [element] : A | CollectionFlow.cs:395:63:395:69 | access to array element |
+| CollectionFlow.cs:395:63:395:66 | access to parameter args [element] : A | CollectionFlow.cs:395:63:395:69 | access to array element |
nodes
-| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
-| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:16:14:16:19 | access to array element | semmle.label | access to array element |
-| CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:18:14:18:23 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | semmle.label | { ..., ... } [field As, element] : A |
-| CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
-| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:34:14:34:17 | access to field As [element] : A | semmle.label | access to field As [element] : A |
-| CollectionFlow.cs:34:14:34:20 | access to array element | semmle.label | access to array element |
-| CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:35:18:35:21 | access to field As [element] : A | semmle.label | access to field As [element] : A |
-| CollectionFlow.cs:36:14:36:24 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
-| CollectionFlow.cs:36:20:36:23 | access to field As [element] : A | semmle.label | access to field As [element] : A |
-| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | semmle.label | [post] access to local variable as [element] : A |
-| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:53:14:53:19 | access to array element | semmle.label | access to array element |
-| CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:55:14:55:23 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:73:14:73:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:75:14:75:28 | call to method ListFirst | semmle.label | call to method ListFirst |
-| CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | semmle.label | object creation of type List [element] : A |
-| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:91:14:91:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:93:14:93:28 | call to method ListFirst | semmle.label | call to method ListFirst |
-| CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:109:14:109:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:111:14:111:28 | call to method ListFirst | semmle.label | call to method ListFirst |
-| CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | semmle.label | [post] access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
-| CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue |
-| CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
-| CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | semmle.label | object creation of type Dictionary [element, property Value] : A |
-| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
-| CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue |
-| CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
-| CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | semmle.label | object creation of type Dictionary [element, property Value] : A |
-| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
-| CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue |
-| CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
-| CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
-| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | semmle.label | object creation of type Dictionary [element, property Key] : A |
-| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A |
-| CollectionFlow.cs:193:14:193:30 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst |
-| CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey |
-| CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | semmle.label | object creation of type Dictionary [element, property Key] : A |
-| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A |
-| CollectionFlow.cs:212:14:212:30 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst |
-| CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey |
-| CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A |
-| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
-| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | semmle.label | SSA def(x) : A |
-| CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:232:18:232:18 | access to local variable x | semmle.label | access to local variable x |
-| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
-| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A | semmle.label | call to method GetEnumerator [property Current] : A |
-| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A | semmle.label | access to local variable enumerator [property Current] : A |
-| CollectionFlow.cs:248:18:248:35 | access to property Current | semmle.label | access to property Current |
-| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A | semmle.label | call to method GetEnumerator [property Current] : A |
-| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A | semmle.label | access to local variable enumerator [property Current] : A |
-| CollectionFlow.cs:266:18:266:35 | access to property Current | semmle.label | access to property Current |
-| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A | semmle.label | [post] access to local variable list [element, property Key] : A |
-| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A | semmle.label | object creation of type KeyValuePair [property Key] : A |
-| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A | semmle.label | access to local variable list [element, property Key] : A |
-| CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A | semmle.label | kvp [property Key] : A |
-| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A | semmle.label | access to parameter kvp [property Key] : A |
-| CollectionFlow.cs:285:18:285:24 | access to property Key | semmle.label | access to property Key |
-| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | semmle.label | [post] access to local variable as [element] : A |
-| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:309:14:309:19 | access to array element | semmle.label | access to array element |
-| CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:311:14:311:23 | call to method First | semmle.label | call to method First |
-| CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
-| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | semmle.label | object creation of type A : A |
-| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
-| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | semmle.label | access to local variable a : A |
-| CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:331:14:331:20 | access to indexer | semmle.label | access to indexer |
-| CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:333:14:333:28 | call to method ListFirst | semmle.label | call to method ListFirst |
-| CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
-| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:13:17:13:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:14:25:14:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
+| CollectionFlow.cs:14:27:14:27 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:15:14:15:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:15:14:15:19 | access to array element | semmle.label | access to array element |
+| CollectionFlow.cs:16:18:16:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:17:14:17:23 | call to method First | semmle.label | call to method First |
+| CollectionFlow.cs:17:20:17:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:31:17:31:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:32:38:32:57 | { ..., ... } [field As, element] : A | semmle.label | { ..., ... } [field As, element] : A |
+| CollectionFlow.cs:32:45:32:55 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A |
+| CollectionFlow.cs:32:53:32:53 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:33:14:33:14 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:33:14:33:17 | access to field As [element] : A | semmle.label | access to field As [element] : A |
+| CollectionFlow.cs:33:14:33:20 | access to array element | semmle.label | access to array element |
+| CollectionFlow.cs:34:18:34:18 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:34:18:34:21 | access to field As [element] : A | semmle.label | access to field As [element] : A |
+| CollectionFlow.cs:35:14:35:24 | call to method First | semmle.label | call to method First |
+| CollectionFlow.cs:35:20:35:20 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A |
+| CollectionFlow.cs:35:20:35:23 | access to field As [element] : A | semmle.label | access to field As [element] : A |
+| CollectionFlow.cs:49:17:49:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:51:9:51:11 | [post] access to local variable as [element] : A | semmle.label | [post] access to local variable as [element] : A |
+| CollectionFlow.cs:51:18:51:18 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:52:14:52:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:52:14:52:19 | access to array element | semmle.label | access to array element |
+| CollectionFlow.cs:53:18:53:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:54:14:54:23 | call to method First | semmle.label | call to method First |
+| CollectionFlow.cs:54:20:54:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A |
+| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:71:9:71:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:71:19:71:19 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:72:14:72:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:72:14:72:20 | access to indexer | semmle.label | access to indexer |
+| CollectionFlow.cs:73:22:73:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:74:14:74:28 | call to method ListFirst | semmle.label | call to method ListFirst |
+| CollectionFlow.cs:74:24:74:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:88:17:88:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:89:20:89:38 | object creation of type List [element] : A | semmle.label | object creation of type List [element] : A |
+| CollectionFlow.cs:89:36:89:36 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:90:14:90:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:90:14:90:20 | access to indexer | semmle.label | access to indexer |
+| CollectionFlow.cs:91:22:91:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:92:14:92:28 | call to method ListFirst | semmle.label | call to method ListFirst |
+| CollectionFlow.cs:92:24:92:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:107:9:107:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A |
+| CollectionFlow.cs:107:18:107:18 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:108:14:108:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer |
+| CollectionFlow.cs:109:22:109:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:110:14:110:28 | call to method ListFirst | semmle.label | call to method ListFirst |
+| CollectionFlow.cs:110:24:110:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A |
+| CollectionFlow.cs:124:17:124:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:126:9:126:12 | [post] access to local variable dict [element, property Value] : A | semmle.label | [post] access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:126:19:126:19 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:127:14:127:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:127:14:127:20 | access to indexer | semmle.label | access to indexer |
+| CollectionFlow.cs:128:23:128:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:129:14:129:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
+| CollectionFlow.cs:129:28:129:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:130:14:130:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue |
+| CollectionFlow.cs:130:29:130:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:131:14:131:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
+| CollectionFlow.cs:131:30:131:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:147:17:147:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:148:20:148:56 | object creation of type Dictionary [element, property Value] : A | semmle.label | object creation of type Dictionary [element, property Value] : A |
+| CollectionFlow.cs:148:52:148:52 | access to local variable a : A | semmle.label | access to local variable a : A |
+| CollectionFlow.cs:149:14:149:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:149:14:149:20 | access to indexer | semmle.label | access to indexer |
+| CollectionFlow.cs:150:23:150:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:151:14:151:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
+| CollectionFlow.cs:151:28:151:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:152:14:152:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue |
+| CollectionFlow.cs:152:29:152:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:153:14:153:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
+| CollectionFlow.cs:153:30:153:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A |
+| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A |
+| CollectionFlow.cs:169:20:169:55 | object creation of type Dictionary