diff --git a/.bazelrc b/.bazelrc index 9a58b60c3ef..a304a7b0e1a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,3 @@ -build --repo_env=CC=clang --repo_env=CXX=clang++ --copt="-std=c++17" +build --repo_env=CC=clang --repo_env=CXX=clang++ --cxxopt="-std=c++17" try-import %workspace%/local.bazelrc diff --git a/.github/workflows/check-qldoc.yml b/.github/workflows/check-qldoc.yml index cc7523162aa..85249fbd92a 100644 --- a/.github/workflows/check-qldoc.yml +++ b/.github/workflows/check-qldoc.yml @@ -27,7 +27,8 @@ jobs: run: | EXIT_CODE=0 # TODO: remove the swift exception from the regex when we fix generated QLdoc - changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!swift)[a-z]*/ql/lib' || true; } | sort -u)" + # TODO: remove the shared exception from the regex when coverage of qlpacks without dbschemes is supported + changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(swift|shared))[a-z]*/ql/lib' || true; } | sort -u)" for pack_dir in ${changed_lib_packs}; do lang="${pack_dir%/ql/lib}" codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 73826e30f9e..fa17f4d6742 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: # uses a compiled language - run: | - dotnet build csharp /p:UseSharedCompilation=false + dotnet build csharp - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@main diff --git a/.github/workflows/csv-coverage-metrics.yml b/.github/workflows/csv-coverage-metrics.yml index 7555533ab98..f18671441cd 100644 --- a/.github/workflows/csv-coverage-metrics.yml +++ b/.github/workflows/csv-coverage-metrics.yml @@ -55,7 +55,7 @@ jobs: DATABASE="${{ runner.temp }}/csharp-database" PROJECT="${{ runner.temp }}/csharp-project" dotnet new classlib --language=C# --output="$PROJECT" - codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj /p:UseSharedCompilation=false' + codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj' - name: Capture coverage information run: | DATABASE="${{ runner.temp }}/csharp-database" diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index 99370014505..53a4157973d 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -5,6 +5,13 @@ on: branches: [main] pull_request: branches: [main] + paths: + - "ql/**" + - "**.qll" + - "**.ql" + - "**.dbscheme" + - "**/qlpack.yml" + - ".github/workflows/ql-for-ql-build.yml" env: CARGO_TERM_COLOR: always @@ -54,7 +61,7 @@ jobs: cp -r ${{ runner.temp }}/queries ${{ runner.temp }}/pack env: CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} - + ### Build the extractor ### - name: Cache entire extractor if: steps.cache-pack.outputs.cache-hit != 'true' @@ -108,7 +115,7 @@ jobs: ### Run the analysis ### - name: Hack codeql-action options run: | - JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]') + JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .resolve.languages=["--search-path", $pack] | .database.init=["--search-path", $pack]') echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV} env: PACK: ${{ runner.temp }}/pack @@ -116,14 +123,14 @@ jobs: - name: Create CodeQL config file run: | echo "paths-ignore:" >> ${CONF} - echo " - ql/ql/test" >> ${CONF} - echo " - \"*/ql/lib/upgrades/\"" >> ${CONF} + echo " - ql/ql/test" >> ${CONF} + echo " - \"*/ql/lib/upgrades/\"" >> ${CONF} echo "disable-default-queries: true" >> ${CONF} echo "queries:" >> ${CONF} echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF} echo "Config file: " cat ${CONF} - env: + env: CONF: ./ql-for-ql-config.yml - name: Initialize CodeQL uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca @@ -139,13 +146,13 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca - with: + with: category: "ql-for-ql" - name: Copy sarif file to CWD run: cp ../results/ql.sarif ./ql-for-ql.sarif - name: Fixup the $scema in sarif # Until https://github.com/microsoft/sarif-vscode-extension/pull/436/ is part in a stable release run: | - sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ql-for-ql.sarif + sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ql-for-ql.sarif - name: Sarif as artifact uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/ruby-build.yml b/.github/workflows/ruby-build.yml index 6ad627aab48..08e2b0b4ab6 100644 --- a/.github/workflows/ruby-build.yml +++ b/.github/workflows/ruby-build.yml @@ -95,6 +95,7 @@ jobs: uses: ./.github/actions/fetch-codeql - name: Build Query Pack run: | + codeql pack create ../shared/ssa --output target/packs codeql pack create ql/lib --output target/packs codeql pack install ql/src codeql pack create ql/src --output target/packs diff --git a/.github/workflows/swift-codegen.yml b/.github/workflows/swift-codegen.yml index 5700045430d..0ce0cc91c21 100644 --- a/.github/workflows/swift-codegen.yml +++ b/.github/workflows/swift-codegen.yml @@ -4,6 +4,8 @@ on: pull_request: paths: - "swift/**" + - "misc/bazel/**" + - "*.bazel*" - .github/workflows/swift-codegen.yml - .github/actions/fetch-codeql/action.yml branches: diff --git a/.github/workflows/swift-integration-tests.yml b/.github/workflows/swift-integration-tests.yml index 4d4248b64e3..b81969f3502 100644 --- a/.github/workflows/swift-integration-tests.yml +++ b/.github/workflows/swift-integration-tests.yml @@ -4,6 +4,8 @@ on: pull_request: paths: - "swift/**" + - "misc/bazel/**" + - "*.bazel*" - .github/workflows/swift-integration-tests.yml - .github/actions/fetch-codeql/action.yml - codeql-workspace.yml @@ -30,6 +32,14 @@ jobs: - name: Build Swift extractor run: | bazel run //swift:create-extractor-pack + - name: Get Swift version + id: get_swift_version + run: | + VERSION=$(bazel run //swift/extractor -- --version | sed -ne 's/.*version \(\S*\).*/\1/p') + echo "::set-output name=version::$VERSION" + - uses: swift-actions/setup-swift@v1 + with: + swift-version: "${{steps.get_swift_version.outputs.version}}" - name: Run integration tests run: | python integration-tests/runner.py diff --git a/.github/workflows/swift-qltest.yml b/.github/workflows/swift-qltest.yml index 3cbcf629c98..ab74e96cd57 100644 --- a/.github/workflows/swift-qltest.yml +++ b/.github/workflows/swift-qltest.yml @@ -4,6 +4,8 @@ on: pull_request: paths: - "swift/**" + - "misc/bazel/**" + - "*.bazel*" - .github/workflows/swift-qltest.yml - .github/actions/fetch-codeql/action.yml - codeql-workspace.yml diff --git a/CODEOWNERS b/CODEOWNERS index 1754d58af63..d5ec29f0b93 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -30,6 +30,8 @@ # Bazel (excluding BUILD.bazel files) WORKSPACE.bazel @github/codeql-ci-reviewers +.bazelversion @github/codeql-ci-reviewers +.bazelrc @github/codeql-ci-reviewers **/*.bzl @github/codeql-ci-reviewers # Documentation etc diff --git a/codeql-workspace.yml b/codeql-workspace.yml index 1bf0510af50..8a7f2bd7a74 100644 --- a/codeql-workspace.yml +++ b/codeql-workspace.yml @@ -4,6 +4,7 @@ provide: - "*/ql/test/qlpack.yml" - "*/ql/examples/qlpack.yml" - "*/ql/consistency-queries/qlpack.yml" + - "shared/*/qlpack.yml" - "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml" - "go/ql/config/legacy-support/qlpack.yml" - "go/build/codeql-extractor-go/codeql-extractor.yml" diff --git a/config/identical-files.json b/config/identical-files.json index b05629f9e96..de7b75c5d48 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -17,6 +17,10 @@ "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", @@ -30,12 +34,14 @@ "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll", + "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll", "swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll" ], "DataFlow Java/C++/C#/Python Common": [ "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll", "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll", @@ -47,6 +53,9 @@ "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", @@ -67,15 +76,17 @@ "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", + "cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll", "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll", "swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll" ], - "DataFlow Java/C# Flow Summaries": [ + "DataFlow Java/C#/Ruby/Python/Swift Flow Summaries": [ "java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll", + "python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll", "swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll" ], "SsaReadPosition Java/C#": [ @@ -460,15 +471,6 @@ "javascript/ql/lib/IDEContextual.qll", "python/ql/lib/analysis/IDEContextual.qll" ], - "SSA C#": [ - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", - "csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll", - "csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll", - "ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll", - "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll", - "swift/ql/lib/codeql/swift/dataflow/internal/SsaImplCommon.qll" - ], "CryptoAlgorithms Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", @@ -540,7 +542,7 @@ "java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll", "javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll", "ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll", - "python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll", + "python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll", "swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll" ], "IncompleteUrlSubstringSanitization": [ @@ -584,22 +586,22 @@ ], "Swift declarations test file": [ "swift/ql/test/extractor-tests/declarations/declarations.swift", - "swift/ql/test/library-tests/parent/declarations.swift" + "swift/ql/test/library-tests/ast/declarations.swift" ], "Swift statements test file": [ "swift/ql/test/extractor-tests/statements/statements.swift", - "swift/ql/test/library-tests/parent/statements.swift" + "swift/ql/test/library-tests/ast/statements.swift" ], "Swift expressions test file": [ "swift/ql/test/extractor-tests/expressions/expressions.swift", - "swift/ql/test/library-tests/parent/expressions.swift" + "swift/ql/test/library-tests/ast/expressions.swift" ], "Swift patterns test file": [ "swift/ql/test/extractor-tests/patterns/patterns.swift", - "swift/ql/test/library-tests/parent/patterns.swift" + "swift/ql/test/library-tests/ast/patterns.swift" ], "IncompleteMultiCharacterSanitization JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll", "ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll" ] -} +} \ No newline at end of file diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs index d37f3e30e66..76acba2eee4 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -299,7 +299,7 @@ namespace Semmle.Autobuild.Cpp.Tests { Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1; Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0; - Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; + Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; diff --git a/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/exprs.ql b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/exprs.ql new file mode 100644 index 00000000000..26f95414fde --- /dev/null +++ b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/exprs.ql @@ -0,0 +1,17 @@ +class Expr extends @expr { + string toString() { none() } +} + +class Location extends @location_expr { + string toString() { none() } +} + +predicate isExprWithNewBuiltin(Expr expr) { + exists(int kind | exprs(expr, kind, _) | 336 <= kind and kind <= 362) +} + +from Expr expr, int kind, int kind_new, Location location +where + exprs(expr, kind, location) and + if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind +select expr, kind_new, location diff --git a/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/old.dbscheme b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/old.dbscheme new file mode 100644 index 00000000000..625f706f2a4 --- /dev/null +++ b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/old.dbscheme @@ -0,0 +1,2190 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/semmlecode.cpp.dbscheme b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..f96ad9b2da4 --- /dev/null +++ b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/semmlecode.cpp.dbscheme @@ -0,0 +1,2136 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/upgrade.properties b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/upgrade.properties new file mode 100644 index 00000000000..d697a16a42f --- /dev/null +++ b/cpp/downgrades/625f706f2a44ae8dc3fc168bfe2637e65c30b012/upgrade.properties @@ -0,0 +1,3 @@ +description: Add new builtin operations +compatibility: partial +exprs.rel: run exprs.qlo diff --git a/cpp/ql/lib/change-notes/2022-09-06-additional-builtin-support.md b/cpp/ql/lib/change-notes/2022-09-06-additional-builtin-support.md new file mode 100644 index 00000000000..625f5001b6e --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-09-06-additional-builtin-support.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`. diff --git a/cpp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md b/cpp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md new file mode 100644 index 00000000000..efdaf85f2ed --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/2022-09-12-uppercase.md b/cpp/ql/lib/change-notes/2022-09-12-uppercase.md new file mode 100644 index 00000000000..996861f1c2c --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-09-12-uppercase.md @@ -0,0 +1,5 @@ +--- +category: deprecated +--- +* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. + The old name still exists as a deprecated alias. \ No newline at end of file diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/dataflow/ProductFlow.qll b/cpp/ql/lib/experimental/semmle/code/cpp/dataflow/ProductFlow.qll new file mode 100644 index 00000000000..2a6066e1b80 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/dataflow/ProductFlow.qll @@ -0,0 +1,165 @@ +import experimental.semmle.code.cpp.ir.dataflow.DataFlow +import experimental.semmle.code.cpp.ir.dataflow.DataFlow2 + +module ProductFlow { + abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `(source1, source2)` is a relevant data flow source. + * + * `source1` and `source2` must belong to the same callable. + */ + predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) { none() } + + /** + * Holds if `(source1, source2)` is a relevant data flow source with initial states `state1` + * and `state2`, respectively. + * + * `source1` and `source2` must belong to the same callable. + */ + predicate isSourcePair( + DataFlow::Node source1, string state1, DataFlow::Node source2, string state2 + ) { + state1 = "" and + state2 = "" and + this.isSourcePair(source1, source2) + } + + /** + * Holds if `(sink1, sink2)` is a relevant data flow sink. + * + * `sink1` and `sink2` must belong to the same callable. + */ + predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) { none() } + + /** + * Holds if `(sink1, sink2)` is a relevant data flow sink with final states `state1` + * and `state2`, respectively. + * + * `sink1` and `sink2` must belong to the same callable. + */ + predicate isSinkPair( + DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2, + DataFlow::FlowState state2 + ) { + state1 = "" and + state2 = "" and + this.isSinkPair(sink1, sink2) + } + + predicate hasFlowPath( + DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1, + DataFlow2::PathNode sink2 + ) { + reachable(this, source1, source2, sink1, sink2) + } + } + + private import Internal + + module Internal { + class Conf1 extends DataFlow::Configuration { + Conf1() { this = "Conf1" } + + override predicate isSource(DataFlow::Node source, string state) { + exists(Configuration conf | conf.isSourcePair(source, state, _, _)) + } + + override predicate isSink(DataFlow::Node sink, string state) { + exists(Configuration conf | conf.isSinkPair(sink, state, _, _)) + } + } + + class Conf2 extends DataFlow2::Configuration { + Conf2() { this = "Conf2" } + + override predicate isSource(DataFlow::Node source, string state) { + exists(Configuration conf, DataFlow::Node source1 | + conf.isSourcePair(source1, _, source, state) and + any(Conf1 c).hasFlow(source1, _) + ) + } + + override predicate isSink(DataFlow::Node sink, string state) { + exists(Configuration conf, DataFlow::Node sink1 | + conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1) + ) + } + } + } + + private predicate reachableInterprocEntry( + Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2, + DataFlow::PathNode node1, DataFlow2::PathNode node2 + ) { + conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and + node1 = source1 and + node2 = source2 + or + exists( + DataFlow::PathNode midEntry1, DataFlow2::PathNode midEntry2, DataFlow::PathNode midExit1, + DataFlow2::PathNode midExit2 + | + reachableInterprocEntry(conf, source1, source2, midEntry1, midEntry2) and + interprocEdgePair(midExit1, midExit2, node1, node2) and + localPathStep1*(midEntry1, midExit1) and + localPathStep2*(midEntry2, midExit2) + ) + } + + private predicate localPathStep1(DataFlow::PathNode pred, DataFlow::PathNode succ) { + DataFlow::PathGraph::edges(pred, succ) and + pragma[only_bind_out](pred.getNode().getEnclosingCallable()) = + pragma[only_bind_out](succ.getNode().getEnclosingCallable()) + } + + private predicate localPathStep2(DataFlow2::PathNode pred, DataFlow2::PathNode succ) { + DataFlow2::PathGraph::edges(pred, succ) and + pragma[only_bind_out](pred.getNode().getEnclosingCallable()) = + pragma[only_bind_out](succ.getNode().getEnclosingCallable()) + } + + pragma[nomagic] + private predicate interprocEdge1( + Declaration predDecl, Declaration succDecl, DataFlow::PathNode pred1, DataFlow::PathNode succ1 + ) { + DataFlow::PathGraph::edges(pred1, succ1) and + predDecl != succDecl and + pred1.getNode().getEnclosingCallable() = predDecl and + succ1.getNode().getEnclosingCallable() = succDecl + } + + pragma[nomagic] + private predicate interprocEdge2( + Declaration predDecl, Declaration succDecl, DataFlow2::PathNode pred2, DataFlow2::PathNode succ2 + ) { + DataFlow2::PathGraph::edges(pred2, succ2) and + predDecl != succDecl and + pred2.getNode().getEnclosingCallable() = predDecl and + succ2.getNode().getEnclosingCallable() = succDecl + } + + private predicate interprocEdgePair( + DataFlow::PathNode pred1, DataFlow2::PathNode pred2, DataFlow::PathNode succ1, + DataFlow2::PathNode succ2 + ) { + exists(Declaration predDecl, Declaration succDecl | + interprocEdge1(predDecl, succDecl, pred1, succ1) and + interprocEdge2(predDecl, succDecl, pred2, succ2) + ) + } + + private predicate reachable( + Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2, + DataFlow::PathNode sink1, DataFlow2::PathNode sink2 + ) { + exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 | + reachableInterprocEntry(conf, source1, source2, mid1, mid2) and + conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and + localPathStep1*(mid1, sink1) and + localPathStep2*(mid2, sink2) + ) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow.qll new file mode 100644 index 00000000000..acb2fbc6808 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow.qll @@ -0,0 +1,26 @@ +/** + * Provides a library for local (intra-procedural) and global (inter-procedural) + * data flow analysis: deciding whether data can flow from a _source_ to a + * _sink_. This library differs from the one in `semmle.code.cpp.dataflow` in that + * this library uses the IR (Intermediate Representation) library, which provides + * a more precise semantic representation of the program, whereas the other dataflow + * library uses the more syntax-oriented ASTs. This library should provide more accurate + * results than the AST-based library in most scenarios. + * + * Unless configured otherwise, _flow_ means that the exact value of + * the source may reach the sink. We do not track flow across pointer + * dereferences or array indexing. + * + * To use global (interprocedural) data flow, extend the class + * `DataFlow::Configuration` as documented on that class. To use local + * (intraprocedural) data flow between expressions, call + * `DataFlow::localExprFlow`. For more general cases of local data flow, call + * `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type + * `DataFlow::Node`. + */ + +import cpp + +module DataFlow { + import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow2.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow2.qll new file mode 100644 index 00000000000..0513bd4ebcb --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow2.qll @@ -0,0 +1,16 @@ +/** + * Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use + * this class when data-flow configurations must depend on each other. Two + * classes extending `DataFlow::Configuration` should never depend on each + * other, but one of them should instead depend on a + * `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a + * `DataFlow4::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation. + */ + +import cpp + +module DataFlow2 { + import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2 +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow3.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow3.qll new file mode 100644 index 00000000000..571b75b37c4 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow3.qll @@ -0,0 +1,16 @@ +/** + * Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use + * this class when data-flow configurations must depend on each other. Two + * classes extending `DataFlow::Configuration` should never depend on each + * other, but one of them should instead depend on a + * `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a + * `DataFlow4::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation. + */ + +import cpp + +module DataFlow3 { + import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3 +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow4.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow4.qll new file mode 100644 index 00000000000..18c21e554f6 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/DataFlow4.qll @@ -0,0 +1,16 @@ +/** + * Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use + * this class when data-flow configurations must depend on each other. Two + * classes extending `DataFlow::Configuration` should never depend on each + * other, but one of them should instead depend on a + * `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a + * `DataFlow4::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation. + */ + +import cpp + +module DataFlow4 { + import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4 +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/ResolveCall.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/ResolveCall.qll new file mode 100644 index 00000000000..bcf2fa8c7db --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/ResolveCall.qll @@ -0,0 +1,23 @@ +/** + * Provides a predicate for non-contextual virtual dispatch and function + * pointer resolution. + */ + +import cpp +private import semmle.code.cpp.ir.ValueNumbering +private import internal.DataFlowDispatch +private import semmle.code.cpp.ir.IR + +/** + * Resolve potential target function(s) for `call`. + * + * If `call` is a call through a function pointer (`ExprCall`) or its target is + * a virtual member function, simple data flow analysis is performed in order + * to identify the possible target(s). + */ +Function resolveCall(Call call) { + exists(CallInstruction callInstruction | + callInstruction.getAst() = call and + result = viableCallable(callInstruction) + ) +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking.qll new file mode 100644 index 00000000000..43064116499 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking.qll @@ -0,0 +1,23 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + * + * We define _taint propagation_ informally to mean that a substantial part of + * the information from the source is preserved at the sink. For example, taint + * propagates from `x` to `x + 100`, but it does not propagate from `x` to `x > + * 100` since we consider a single bit of information to be too little. + * + * To use global (interprocedural) taint tracking, extend the class + * `TaintTracking::Configuration` as documented on that class. To use local + * (intraprocedural) taint tracking between expressions, call + * `TaintTracking::localExprTaint`. For more general cases of local taint + * tracking, call `TaintTracking::localTaint` or + * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`. + */ + +import semmle.code.cpp.ir.dataflow.DataFlow +import semmle.code.cpp.ir.dataflow.DataFlow2 + +module TaintTracking { + import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking2.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking2.qll new file mode 100644 index 00000000000..aa9fd392803 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking2.qll @@ -0,0 +1,15 @@ +/** + * Provides a `TaintTracking2` module, which is a copy of the `TaintTracking` + * module. Use this class when data-flow configurations or taint-tracking + * configurations must depend on each other. Two classes extending + * `DataFlow::Configuration` should never depend on each other, but one of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The + * `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and + * `TaintTracking2::Configuration` extends `DataFlow2::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation. + */ +module TaintTracking2 { + import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking3.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking3.qll new file mode 100644 index 00000000000..bcd35ccd02f --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/TaintTracking3.qll @@ -0,0 +1,15 @@ +/** + * Provides a `TaintTracking3` module, which is a copy of the `TaintTracking` + * module. Use this class when data-flow configurations or taint-tracking + * configurations must depend on each other. Two classes extending + * `DataFlow::Configuration` should never depend on each other, but one of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The + * `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and + * `TaintTracking2::Configuration` extends `DataFlow2::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation. + */ +module TaintTracking3 { + import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll new file mode 100644 index 00000000000..f92612e77af --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -0,0 +1,273 @@ +private import cpp +private import semmle.code.cpp.ir.IR +private import experimental.semmle.code.cpp.ir.dataflow.DataFlow +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import DataFlowImplCommon as DataFlowImplCommon + +/** + * Gets a function that might be called by `call`. + */ +cached +Function viableCallable(CallInstruction call) { + DataFlowImplCommon::forceCachingInSameStage() and + result = call.getStaticCallTarget() + or + // If the target of the call does not have a body in the snapshot, it might + // be because the target is just a header declaration, and the real target + // will be determined at run time when the caller and callee are linked + // together by the operating system's dynamic linker. In case a _unique_ + // function with the right signature is present in the database, we return + // that as a potential callee. + exists(string qualifiedName, int nparams | + callSignatureWithoutBody(qualifiedName, nparams, call) and + functionSignatureWithBody(qualifiedName, nparams, result) and + strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1 + ) + or + // Virtual dispatch + result = call.(VirtualDispatch::DataSensitiveCall).resolve() +} + +/** + * Provides virtual dispatch support compatible with the original + * implementation of `semmle.code.cpp.security.TaintTracking`. + */ +private module VirtualDispatch { + /** A call that may dispatch differently depending on the qualifier value. */ + abstract class DataSensitiveCall extends DataFlowCall { + /** + * Gets the node whose value determines the target of this call. This node + * could be the qualifier of a virtual dispatch or the function-pointer + * expression in a call to a function pointer. What they have in common is + * that we need to find out which data flows there, and then it's up to the + * `resolve` predicate to stitch that information together and resolve the + * call. + */ + abstract DataFlow::Node getDispatchValue(); + + /** Gets a candidate target for this call. */ + abstract Function resolve(); + + /** + * Whether `src` can flow to this call. + * + * Searches backwards from `getDispatchValue()` to `src`. The `allowFromArg` + * parameter is true when the search is allowed to continue backwards into + * a parameter; non-recursive callers should pass `_` for `allowFromArg`. + */ + predicate flowsFrom(DataFlow::Node src, boolean allowFromArg) { + src = this.getDispatchValue() and allowFromArg = true + or + exists(DataFlow::Node other, boolean allowOtherFromArg | + this.flowsFrom(other, allowOtherFromArg) + | + // Call argument + exists(DataFlowCall call, Position i | + other + .(DataFlow::ParameterNode) + .isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and + src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i))) + ) and + allowOtherFromArg = true and + allowFromArg = true + or + // Call return + exists(DataFlowCall call, ReturnKind returnKind | + other = getAnOutNode(call, returnKind) and + returnNodeWithKindAndEnclosingCallable(src, returnKind, call.getStaticCallTarget()) + ) and + allowFromArg = false + or + // Local flow + DataFlow::localFlowStep(src, other) and + allowFromArg = allowOtherFromArg + or + // Flow from global variable to load. + exists(LoadInstruction load, GlobalOrNamespaceVariable var | + var = src.asVariable() and + other.asInstruction() = load and + addressOfGlobal(load.getSourceAddress(), var) and + // The `allowFromArg` concept doesn't play a role when `src` is a + // global variable, so we just set it to a single arbitrary value for + // performance. + allowFromArg = true + ) + or + // Flow from store to global variable. + exists(StoreInstruction store, GlobalOrNamespaceVariable var | + var = other.asVariable() and + store = src.asInstruction() and + storeIntoGlobal(store, var) and + // Setting `allowFromArg` to `true` like in the base case means we + // treat a store to a global variable like the dispatch itself: flow + // may come from anywhere. + allowFromArg = true + ) + ) + } + } + + pragma[noinline] + private predicate storeIntoGlobal(StoreInstruction store, GlobalOrNamespaceVariable var) { + addressOfGlobal(store.getDestinationAddress(), var) + } + + /** Holds if `addressInstr` is an instruction that produces the address of `var`. */ + private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) { + // Access directly to the global variable + addressInstr.(VariableAddressInstruction).getAstVariable() = var + or + // Access to a field on a global union + exists(FieldAddressInstruction fa | + fa = addressInstr and + fa.getObjectAddress().(VariableAddressInstruction).getAstVariable() = var and + fa.getField().getDeclaringType() instanceof Union + ) + } + + /** + * A ReturnNode with its ReturnKind and its enclosing callable. + * + * Used to fix a join ordering issue in flowsFrom. + */ + pragma[noinline] + private predicate returnNodeWithKindAndEnclosingCallable( + ReturnNode node, ReturnKind kind, DataFlowCallable callable + ) { + node.getKind() = kind and + node.getEnclosingCallable() = callable + } + + /** Call through a function pointer. */ + private class DataSensitiveExprCall extends DataSensitiveCall { + DataSensitiveExprCall() { not exists(this.getStaticCallTarget()) } + + override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getCallTarget() } + + override Function resolve() { + exists(FunctionInstruction fi | + this.flowsFrom(DataFlow::instructionNode(fi), _) and + result = fi.getFunctionSymbol() + ) and + ( + this.getNumberOfArguments() <= result.getEffectiveNumberOfParameters() and + this.getNumberOfArguments() >= result.getEffectiveNumberOfParameters() + or + result.isVarargs() + ) + } + } + + /** Call to a virtual function. */ + private class DataSensitiveOverriddenFunctionCall extends DataSensitiveCall { + DataSensitiveOverriddenFunctionCall() { + exists(this.getStaticCallTarget().(VirtualFunction).getAnOverridingFunction()) + } + + override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getThisArgument() } + + override MemberFunction resolve() { + exists(Class overridingClass | + this.overrideMayAffectCall(overridingClass, result) and + this.hasFlowFromCastFrom(overridingClass) + ) + } + + /** + * Holds if `this` is a virtual function call whose static target is + * overridden by `overridingFunction` in `overridingClass`. + */ + pragma[noinline] + private predicate overrideMayAffectCall(Class overridingClass, MemberFunction overridingFunction) { + overridingFunction.getAnOverriddenFunction+() = this.getStaticCallTarget().(VirtualFunction) and + overridingFunction.getDeclaringType() = overridingClass + } + + /** + * Holds if the qualifier of `this` has flow from an upcast from + * `derivedClass`. + */ + pragma[noinline] + private predicate hasFlowFromCastFrom(Class derivedClass) { + exists(ConvertToBaseInstruction toBase | + this.flowsFrom(DataFlow::instructionNode(toBase), _) and + derivedClass = toBase.getDerivedClass() + ) + } + } +} + +/** + * Holds if `f` is a function with a body that has name `qualifiedName` and + * `nparams` parameter count. See `functionSignature`. + */ +private predicate functionSignatureWithBody(string qualifiedName, int nparams, Function f) { + functionSignature(f, qualifiedName, nparams) and + exists(f.getBlock()) +} + +/** + * Holds if the target of `call` is a function _with no definition_ that has + * name `qualifiedName` and `nparams` parameter count. See `functionSignature`. + */ +pragma[noinline] +private predicate callSignatureWithoutBody(string qualifiedName, int nparams, CallInstruction call) { + exists(Function target | + target = call.getStaticCallTarget() and + not exists(target.getBlock()) and + functionSignature(target, qualifiedName, nparams) + ) +} + +/** + * Holds if `f` has name `qualifiedName` and `nparams` parameter count. This is + * an approximation of its signature for the purpose of matching functions that + * might be the same across link targets. + */ +private predicate functionSignature(Function f, string qualifiedName, int nparams) { + qualifiedName = f.getQualifiedName() and + nparams = f.getNumberOfParameters() and + not f.isStatic() +} + +/** + * 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) { + 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) { + 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() + ) +} + +/** Holds if arguments at position `apos` match parameters at position `ppos`. */ +pragma[inline] +predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll new file mode 100644 index 00000000000..468f8640a78 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -0,0 +1,4450 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. This file exists in several identical + * copies, allowing queries to use multiple `Configuration` classes that depend + * on each other without introducing mutual recursion among those configurations. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ```ql + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(Node source) { none() } + + /** + * Holds if `source` is a relevant data flow source with the given initial + * `state`. + */ + predicate isSource(Node source, FlowState state) { none() } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(Node sink) { none() } + + /** + * Holds if `sink` is a relevant data flow sink accepting `state`. + */ + predicate isSink(Node source, FlowState state) { none() } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** + * Holds if data flow through `node` is prohibited when the flow state is + * `state`. + */ + predicate isBarrier(Node node, FlowState state) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited when + * the flow state is `state` + */ + deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) { + none() + } + + /** + * Holds if an arbitrary number of implicit read steps of content `c` may be + * taken at `node`. + */ + predicate allowImplicitRead(Node node, ContentSet c) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` + * measured in approximate number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } + + /** + * Holds if there is a partial data flow path from `node` to `sink`. The + * approximate distance between `node` and the closest sink is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards source definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sinks is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + * + * Note that reverse flow has slightly lower precision than the corresponding + * forward flow, as reverse flow disregards type pruning among other features. + */ + final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) { + revPartialFlow(node, sink, this) and + dist = node.getSinkDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSource(n, _)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n | this.isSink(n, _)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0 + or + super.hasFlow(source, sink) + } +} + +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 class ArgNodeEx extends NodeEx { + ArgNodeEx() { this.asNode() instanceof ArgNode } +} + +private class ParamNodeEx extends NodeEx { + ParamNodeEx() { this.asNode() instanceof ParamNode } + + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + this.asNode().(ParamNode).isParameterOf(c, pos) + } + + ParameterPosition getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } +} + +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) + | + config.isSource(n) or config.isSource(n, _) + ) +} + +private predicate outBarrier(NodeEx node, Configuration config) { + exists(Node n | + node.asNode() = n and + config.isBarrierOut(n) + | + config.isSink(n) or config.isSink(n, _) + ) +} + +/** A bridge class to access the deprecated `isBarrierGuard`. */ +private class BarrierGuardGuardedNodeBridge extends Unit { + abstract predicate guardedNode(Node n, Configuration config); + + abstract predicate guardedNode(Node n, FlowState state, Configuration config); +} + +private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge { + deprecated override predicate guardedNode(Node n, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g) and + n = g.getAGuardedNode() + ) + } + + deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g, state) and + n = g.getAGuardedNode() + ) + } +} + +pragma[nomagic] +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) and + not config.isSource(n, _) + or + config.isBarrierOut(n) and + not config.isSink(n) and + not config.isSink(n, _) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config) + ) +} + +pragma[nomagic] +private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) { + exists(Node n | node.asNode() = n | + config.isBarrier(n, state) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config) + ) +} + +pragma[nomagic] +private predicate sourceNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSource(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSource(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +pragma[nomagic] +private predicate sinkNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSink(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSink(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +/** Provides the relevant barriers for a step from `node1` to `node2`. */ +pragma[inline] +private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) { + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.asNode() = n and + node2.isImplicitReadNode(n, false) and + not fullBarrier(node1, config) + ) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.isImplicitReadNode(n, true) and + node2.asNode() = n and + not fullBarrier(node2, config) + ) +} + +private predicate additionalLocalStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) + ) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate additionalJumpStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +pragma[nomagic] +private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and + stepFilter(node1, node2, config) + or + exists(Node n | + node2.isImplicitReadNode(n, true) and + node1.isImplicitReadNode(n, _) and + config.allowImplicitRead(n, c) + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { + exists(ContentSet cs | + readSet(node1, cs, node2, config) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate clearsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + clearsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + +pragma[nomagic] +private predicate store( + NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config +) { + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and + read(_, tc.getContent(), _, config) and + stepFilter(node1, node2, 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()) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private module Stage1 implements StageSig { + class ApApprox = Unit; + + class Ap = Unit; + + class ApOption = Unit; + + class Cc = boolean; + + /* Begin: Stage 1 logic. */ + /** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `cc` records whether the node is reached through an + * argument in a call. + */ + predicate fwdFlow(NodeEx node, Cc cc, Configuration config) { + sourceNode(node, _, config) and + if hasSourceCallCtx(config) then cc = true else cc = false + or + exists(NodeEx mid | fwdFlow(mid, cc, config) | + localFlowStep(mid, node, config) or + additionalLocalFlowStep(mid, node, config) or + additionalLocalStateStep(mid, _, node, _, config) + ) + or + exists(NodeEx mid | fwdFlow(mid, _, config) and cc = false | + jumpStep(mid, node, config) or + additionalJumpStep(mid, node, config) or + additionalJumpStateStep(mid, _, node, _, config) + ) + or + // store + exists(NodeEx mid | + useFieldFlow(config) and + fwdFlow(mid, cc, config) and + store(mid, _, node, _, config) + ) + or + // read + exists(ContentSet c | + fwdFlowReadSet(c, node, cc, config) and + fwdFlowConsCandSet(c, _, config) + ) + or + // flow into a callable + exists(NodeEx arg | + fwdFlow(arg, _, config) and + viableParamArgEx(_, node, arg) and + cc = true and + not fullBarrier(node, config) + ) + or + // flow out of a callable + exists(DataFlowCall call | + fwdFlowOut(call, node, false, config) and + cc = false + or + fwdFlowOutFromArg(call, node, config) and + fwdFlowIsEntered(call, cc, config) + ) + } + + private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) } + + pragma[nomagic] + private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) { + exists(NodeEx mid | + fwdFlow(mid, cc, config) and + readSet(mid, c, node, config) + ) + } + + /** + * Holds if `c` is the target of a store in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, TypedContent tc | + not fullBarrier(node, config) and + useFieldFlow(config) and + fwdFlow(mid, _, config) and + store(mid, tc, node, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `cs` may be interpreted in a read as the target of some store + * into `c`, in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) { + fwdFlowConsCand(c, config) and + c = cs.getAReadContent() + } + + pragma[nomagic] + private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) { + exists(RetNodeEx ret | + fwdFlow(ret, cc, config) and + ret.getReturnPosition() = pos + ) + } + + pragma[nomagic] + private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) { + exists(ReturnPosition pos | + fwdFlowReturnPosition(pos, cc, config) and + viableReturnPosOutEx(call, pos, out) and + not fullBarrier(out, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) { + fwdFlowOut(call, out, true, config) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { + exists(ArgNodeEx arg | + fwdFlow(arg, cc, config) and + viableParamArgEx(call, _, arg) + ) + } + + private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1 | + additionalLocalStateStep(node1, state1, _, state2, config) or + additionalJumpStateStep(node1, state1, _, state2, config) + | + fwdFlow(node1, config) + ) + } + + private predicate fwdFlowState(FlowState state, Configuration config) { + sourceNode(_, state, config) + or + exists(FlowState state0 | + fwdFlowState(state0, config) and + stateStepFwd(state0, state, config) + ) + } + + /** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ + pragma[nomagic] + predicate revFlow(NodeEx node, boolean toReturn, Configuration config) { + revFlow0(node, toReturn, config) and + fwdFlow(node, config) + } + + pragma[nomagic] + private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { + exists(FlowState state | + fwdFlow(node, pragma[only_bind_into](config)) and + sinkNode(node, state, config) and + fwdFlowState(state, pragma[only_bind_into](config)) and + if hasSinkCallCtx(config) then toReturn = true else toReturn = false + ) + or + exists(NodeEx mid | revFlow(mid, toReturn, config) | + localFlowStep(node, mid, config) or + additionalLocalFlowStep(node, mid, config) or + additionalLocalStateStep(node, _, mid, _, config) + ) + or + exists(NodeEx mid | revFlow(mid, _, config) and toReturn = false | + jumpStep(node, mid, config) or + additionalJumpStep(node, mid, config) or + additionalJumpStateStep(node, _, mid, _, config) + ) + or + // store + exists(Content c | + revFlowStore(c, node, toReturn, config) and + revFlowConsCand(c, config) + ) + or + // read + exists(NodeEx mid, ContentSet c | + readSet(node, c, mid, config) and + fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and + revFlow(mid, toReturn, pragma[only_bind_into](config)) + ) + or + // flow into a callable + exists(DataFlowCall call | + revFlowIn(call, node, false, config) and + toReturn = false + or + revFlowInToReturn(call, node, config) and + revFlowIsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + revFlowOut(pos, config) and + node.(RetNodeEx).getReturnPosition() = pos and + toReturn = true + ) + } + + /** + * Holds if `c` is the target of a read in the flow covered by `revFlow`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, ContentSet cs | + fwdFlow(node, pragma[only_bind_into](config)) and + readSet(node, cs, mid, config) and + fwdFlowConsCandSet(cs, 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, 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, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `c` is the target of both a read and a store in the flow covered + * by `revFlow`. + */ + pragma[nomagic] + predicate revFlowIsReadAndStored(Content c, Configuration conf) { + revFlowConsCand(c, conf) and + revFlowStore(c, _, _, conf) + } + + pragma[nomagic] + predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config + ) { + fwdFlowReturnPosition(pos, _, config) and + viableReturnPosOutEx(call, pos, out) + } + + pragma[nomagic] + private predicate revFlowOut(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, NodeEx out | + revFlow(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) + } + + pragma[nomagic] + predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config + ) { + viableParamArgEx(call, p, arg) and + fwdFlow(arg, config) + } + + pragma[nomagic] + 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, ArgNodeEx arg, Configuration config) { + revFlowIn(call, arg, true, config) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(NodeEx out | + revFlow(out, toReturn, config) and + fwdFlowOutFromArg(call, out, config) + ) + } + + private predicate stateStepRev(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + additionalLocalStateStep(node1, state1, node2, state2, config) or + additionalJumpStateStep(node1, state1, node2, state2, config) + | + revFlow(node1, _, pragma[only_bind_into](config)) and + revFlow(node2, _, pragma[only_bind_into](config)) and + fwdFlowState(state1, pragma[only_bind_into](config)) and + fwdFlowState(state2, pragma[only_bind_into](config)) + ) + } + + predicate revFlowState(FlowState state, Configuration config) { + exists(NodeEx node | + sinkNode(node, state, config) and + revFlow(node, _, pragma[only_bind_into](config)) and + fwdFlowState(state, pragma[only_bind_into](config)) + ) + or + exists(FlowState state0 | + revFlowState(state0, config) and + stateStepRev(state, state0, config) + ) + } + + pragma[nomagic] + predicate storeStepCand( + 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, config) and + c = tc.getContent() and + exists(ap1) + ) + } + + pragma[nomagic] + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + read(n1, c, n2, pragma[only_bind_into](config)) and + revFlow(n2, pragma[only_bind_into](config)) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, _, pragma[only_bind_into](config)) and + exists(state) and + exists(ap) + } + + private predicate throughFlowNodeCand(NodeEx node, Configuration config) { + revFlow(node, true, config) and + fwdFlow(node, true, config) and + not inBarrier(node, config) and + not outBarrier(node, config) + } + + /** Holds if flow may return from `callable`. */ + pragma[nomagic] + private predicate returnFlowCallableNodeCand( + DataFlowCallable callable, ReturnKindExt kind, Configuration config + ) { + exists(RetNodeEx ret | + throughFlowNodeCand(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) + } + + /** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ + pragma[nomagic] + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand(p, config) and + returnFlowCallableNodeCand(c, kind, config) and + p.getEnclosingCallable() = c and + exists(ap) and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists(ArgNodeEx arg, boolean toReturn | + revFlow(arg, toReturn, config) and + revFlowInToReturn(call, arg, config) and + revFlowIsReturned(call, toReturn, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true and + nodes = count(NodeEx node | fwdFlow(node, config)) and + fields = count(Content f0 | fwdFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | fwdFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config)) + or + fwd = false and + nodes = count(NodeEx node | revFlow(node, _, config)) and + fields = count(Content f0 | revFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | revFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | revFlow(n, b, config)) + } + /* End: Stage 1 logic. */ +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) { + Stage1::revFlow(node2, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +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, NodeEx out, Configuration config +) { + Stage1::revFlow(out, config) and + Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config +) { + viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and + Stage1::revFlow(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config +) { + Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and + Stage1::revFlow(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + Stage1::revFlow(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(NodeEx n1, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(NodeEx n2, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +private signature module StageSig { + class Ap; + + predicate revFlow(NodeEx node, Configuration config); + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); + + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); + + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ); + + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config); +} + +private module MkStage { + class ApApprox = PrevStage::Ap; + + signature module StageParam { + class Ap; + + class ApNil extends Ap; + + bindingset[result, ap] + ApApprox getApprox(Ap ap); + + ApNil getApNil(NodeEx node); + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail); + + Content getHeadContent(Ap ap); + + class ApOption; + + ApOption apNone(); + + ApOption apSome(Ap ap); + + class Cc; + + class CcCall extends Cc; + + // TODO: member predicate on CcCall + predicate matchesCall(CcCall cc, DataFlowCall call); + + class CcNoCall extends Cc; + + Cc ccNone(); + + CcCall ccSomeCall(); + + class LocalCc; + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc); + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc); + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc); + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ); + + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config + ); + + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config + ); + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config); + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType); + } + + module Stage implements StageSig { + import Param + + /* Begin: Stage logic. */ + bindingset[result, apa] + private ApApprox unbindApa(ApApprox apa) { + pragma[only_bind_out](apa) = pragma[only_bind_out](result) + } + + pragma[nomagic] + private predicate flowThroughOutOfCall( + DataFlowCall call, CcCall ccc, 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(_, ret.getEnclosingCallable(), _, + pragma[only_bind_into](config)) and + matchesCall(ccc, call) + } + + /** + * Holds if `node` is reachable with access path `ap` from a source in the + * configuration `config`. + * + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ + pragma[nomagic] + predicate fwdFlow( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + fwdFlow0(node, state, cc, argAp, ap, config) and + PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and + filter(node, state, ap, config) + } + + pragma[nomagic] + private predicate fwdFlow0( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + sourceNode(node, state, config) and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and + argAp = apNone() and + ap = getApNil(node) + or + exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | + fwdFlow(mid, state0, cc, argAp, ap0, config) and + localCc = getLocalCc(mid, cc) + | + localStep(mid, state0, node, state, true, _, config, localCc) and + ap = ap0 + or + localStep(mid, state0, node, state, false, ap, config, localCc) and + ap0 instanceof ApNil + ) + or + exists(NodeEx mid | + fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + jumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() + ) + or + exists(NodeEx mid, ApNil nil | + fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStateStep(mid, state0, node, state, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + // store + exists(TypedContent tc, Ap ap0 | + fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and + ap = apCons(tc, ap0) + ) + or + // read + exists(Ap ap0, Content c | + fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and + fwdFlowConsCand(ap0, c, ap, config) + ) + or + // flow into a callable + exists(ApApprox apa | + fwdFlowIn(_, node, state, _, cc, _, ap, config) and + apa = getApprox(ap) and + if PrevStage::parameterMayFlowThrough(node, _, apa, config) + then argAp = apSome(ap) + else argAp = apNone() + ) + or + // flow out of a callable + fwdFlowOutNotFromArg(node, state, cc, argAp, ap, config) + or + exists(DataFlowCall call, Ap argAp0 | + fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and + fwdFlowIsEntered(call, cc, argAp, argAp0, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowStore( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + exists(DataFlowType contentType | + fwdFlow(node1, state, cc, argAp, ap1, config) and + PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and + typecheckStore(ap1, contentType) + ) + } + + /** + * Holds if forward flow with access path `tail` reaches a store of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(TypedContent tc | + fwdFlowStore(_, tail, tc, _, _, _, _, config) and + tc.getContent() = c and + cons = apCons(tc, tail) + ) + } + + pragma[nomagic] + private predicate fwdFlowRead( + Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + fwdFlow(node1, state, cc, argAp, ap, config) and + PrevStage::readStepCand(node1, c, node2, config) and + getHeadContent(ap) = c + } + + pragma[nomagic] + private predicate fwdFlowIn( + DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, + Ap ap, Configuration config + ) { + exists(ArgNodeEx arg, boolean allowsFieldFlow | + fwdFlow(arg, state, outercc, argAp, ap, config) and + flowIntoCall(call, arg, p, allowsFieldFlow, config) and + innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutNotFromArg( + NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config + ) { + exists( + DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, + DataFlowCallable inner + | + fwdFlow(ret, state, innercc, argAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + inner = ret.getEnclosingCallable() and + ccOut = getCallContextReturn(inner, call, innercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg( + DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc | + fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and + flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow` + * and data might flow through the target callable and back out at `call`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered( + DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p | + fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and + PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) + ) + } + + pragma[nomagic] + private predicate storeStepFwd( + 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( + 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, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, + pragma[only_bind_into](config)) and + fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate flowThroughIntoCall( + 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 + PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and + callMayFlowThroughFwd(call, pragma[only_bind_into](config)) + } + + pragma[nomagic] + private predicate returnNodeMayFlowThrough( + RetNodeEx ret, FlowState state, Ap ap, Configuration config + ) { + fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config) + } + + /** + * Holds if `node` with access path `ap` is part of a path from a source to a + * sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from the + * enclosing callable in order to reach a sink, and if so, `returnAp` records + * the access path of the returned value. + */ + pragma[nomagic] + predicate revFlow( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + revFlow0(node, state, toReturn, returnAp, ap, config) and + fwdFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + private predicate revFlow0( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + fwdFlow(node, state, _, _, ap, config) and + sinkNode(node, state, config) and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and + returnAp = apNone() and + ap instanceof ApNil + or + exists(NodeEx mid, FlowState state0 | + localStep(node, state, mid, state0, true, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, ap, config) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and + ap instanceof ApNil + ) + or + exists(NodeEx mid | + jumpStep(node, mid, config) and + revFlow(mid, state, _, _, ap, config) and + toReturn = false and + returnAp = apNone() + ) + or + 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), state, _, _, nil, pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and + additionalJumpStateStep(node, state, mid, state0, config) and + revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, + pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + // store + exists(Ap ap0, Content c | + revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and + revFlowConsCand(ap0, c, ap, config) + ) + or + // read + exists(NodeEx mid, Ap ap0 | + revFlow(mid, state, toReturn, returnAp, ap0, config) and + readStepFwd(node, ap, _, mid, ap0, config) + ) + or + // flow into a callable + revFlowInNotToReturn(node, state, returnAp, ap, config) and + toReturn = false + or + exists(DataFlowCall call, Ap returnAp0 | + revFlowInToReturn(call, node, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + or + // flow out of a callable + revFlowOut(_, node, state, _, _, ap, config) and + toReturn = true and + if returnNodeMayFlowThrough(node, state, ap, config) + then returnAp = apSome(ap) + else returnAp = apNone() + } + + pragma[nomagic] + private predicate revFlowStore( + Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, + boolean toReturn, ApOption returnAp, Configuration config + ) { + revFlow(mid, state, toReturn, returnAp, ap0, config) and + storeStepFwd(node, ap, tc, mid, ap0, config) and + tc.getContent() = c + } + + /** + * Holds if reverse flow with access path `tail` reaches a read of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(NodeEx mid, Ap tail0 | + revFlow(mid, _, _, _, tail, config) and + tail = pragma[only_bind_into](tail0) and + readStepFwd(_, cons, c, mid, tail0, config) + ) + } + + pragma[nomagic] + private predicate revFlowOut( + DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, + Configuration config + ) { + exists(NodeEx out, boolean allowsFieldFlow | + revFlow(out, state, toReturn, returnAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInNotToReturn( + ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, false, returnAp, ap, config) and + flowIntoCall(_, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInToReturn( + DataFlowCall call, ArgNodeEx arg, FlowState state, Ap returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, true, apSome(returnAp), ap, config) and + flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned( + DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, FlowState state, CcCall ccc | + revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and + fwdFlow(ret, state, ccc, apSome(_), ap, config) and + matchesCall(ccc, call) + ) + } + + pragma[nomagic] + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ) { + exists(Ap ap2, Content c | + PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and + revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and + revFlowConsCand(ap2, c, ap1, 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 + revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _, _, + pragma[only_bind_into](config)) + ) + } + + predicate revFlow(NodeEx node, FlowState state, Configuration config) { + revFlow(node, state, _, _, _, config) + } + + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, ap, config) + } + + private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepFwd(_, ap, tc, _, _, config) + } + + private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepCand(_, ap, tc, _, _, config) + } + + private predicate validAp(Ap ap, Configuration config) { + revFlow(_, _, _, _, ap, config) and ap instanceof ApNil + or + exists(TypedContent head, Ap tail | + consCand(head, tail, config) and + ap = apCons(head, tail) + ) + } + + predicate consCand(TypedContent tc, Ap ap, Configuration config) { + revConsCand(tc, ap, config) and + validAp(ap, config) + } + + pragma[noinline] + private predicate parameterFlow( + ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config + ) { + revFlow(p, _, true, apSome(ap0), ap, config) and + c = p.getEnclosingCallable() + } + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | + parameterFlow(p, ap, ap0, c, config) and + c = ret.getEnclosingCallable() and + revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), + pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and + fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and + kind = ret.getKind() and + p.getPosition() = pos and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists( + Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap + | + revFlow(arg, state, toReturn, returnAp, ap, config) and + revFlowInToReturn(call, arg, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true 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 + states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(n, state, cc, argAp, ap, config) + ) + or + fwd = false 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 + states = count(FlowState state | revFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | + revFlow(n, state, b, retAp, ap, config) + ) + } + /* End: Stage logic. */ + } +} + +private module BooleanCallContext { + class Cc extends boolean { + Cc() { this in [true, false] } + } + + class CcCall extends Cc { + CcCall() { this = true } + } + + /** Holds if the call context may be `call`. */ + predicate matchesCall(CcCall cc, DataFlowCall call) { any() } + + class CcNoCall extends Cc { + CcNoCall() { this = false } + } + + Cc ccNone() { result = false } + + CcCall ccSomeCall() { result = true } + + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } +} + +private module Level1CallContext { + class Cc = CallContext; + + class CcCall = CallContextCall; + + pragma[inline] + predicate matchesCall(CcCall cc, DataFlowCall call) { cc.matchesCall(call) } + + class CcNoCall = CallContextNoCall; + + Cc ccNone() { result instanceof CallContextAny } + + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + + module NoLocalCallContext { + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } + } + + module LocalCallContext { + class LocalCc = LocalCallContext; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { + result = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + node.getEnclosingCallable()) + } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall() + } + } + + bindingset[call, c, innercc] + 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() + } +} + +private module Stage2Param implements MkStage::StageParam { + private module PrevStage = Stage1; + + class Ap extends boolean { + Ap() { this in [true, false] } + } + + class ApNil extends Ap { + ApNil() { this = false } + } + + bindingset[result, ap] + PrevStage::Ap getApprox(Ap ap) { any() } + + ApNil getApNil(NodeEx node) { Stage1::revFlow(node, _) and exists(result) } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) } + + pragma[inline] + Content getHeadContent(Ap ap) { exists(result) and ap = true } + + class ApOption = BooleanOption; + + ApOption apNone() { result = TBooleanNone() } + + ApOption apSome(Ap ap) { result = TBooleanSome(ap) } + + import Level1CallContext + import NoLocalCallContext + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + ( + preservesValue = true and + localFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalStateStep(node1, state1, node2, state2, config) + ) and + exists(ap) and + exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand1/5; + + predicate flowIntoCall = flowIntoCallNodeCand1/5; + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + PrevStage::revFlowState(state, pragma[only_bind_into](config)) and + exists(ap) and + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage2 implements StageSig { + import MkStage::Stage +} + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +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 NodeEx { + FlowCheckNode() { + castNode(this.asNode()) or + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) + } + } + + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) { + Stage2::revFlow(node, state, config) and + ( + sourceNode(node, state, config) + or + jumpStep(_, node, config) + or + additionalJumpStep(_, node, config) + or + additionalJumpStateStep(_, _, node, state, config) + or + node instanceof ParamNodeEx + or + node.asNode() instanceof OutNodeExt + or + Stage2::storeStepCand(_, _, _, node, _, config) + or + Stage2::readStepCand(_, _, node, config) + or + node instanceof FlowCheckNode + or + exists(FlowState s | + additionalLocalStateStep(_, s, node, state, config) and + s != state + ) + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(NodeEx node, FlowState state, Configuration config) { + exists(NodeEx next | Stage2::revFlow(next, state, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + Stage2::storeStepCand(node, _, _, next, _, config) or + Stage2::readStepCand(node, _, next, config) + ) + or + exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) | + additionalJumpStateStep(node, state, next, s, config) + or + additionalLocalStateStep(node, state, next, s, config) and + s != state + ) + or + Stage2::revFlow(node, state, config) and + node instanceof FlowCheckNode + or + sinkNode(node, state, config) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, Configuration config + ) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 and + Stage2::revFlow(node1, pragma[only_bind_into](state1), false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, pragma[only_bind_into](state2), false, + pragma[only_bind_into](config)) + or + additionalLocalStateStep(node1, state1, node2, state2, config) and + Stage2::revFlow(node1, state1, false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, state2, false, pragma[only_bind_into](config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t, + Configuration config, LocalCallContext cc + ) { + not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = node1.getDataFlowType() and // irrelevant dummy value + Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config)) + or + additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and + preservesValue = false and + t = node2.getDataFlowType() + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) + or + exists(NodeEx mid | + localFlowStepPlus(node1, pragma[only_bind_into](state), 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](state), pragma[only_bind_into](config)) + ) + or + exists(NodeEx mid | + localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and + additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and + not mid instanceof FlowCheckNode and + preservesValue = false and + t = node2.getDataFlowType() + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + AccessPathFrontNil apf, Configuration config, LocalCallContext callContext + ) { + localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, state1, config) and + state1 = state2 + or + additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and + state1 != state2 and + preservesValue = false and + apf = TFrontNil(node2.getDataFlowType()) and + callContext.relevantFor(node1.getEnclosingCallable()) and + not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | + isUnreachableInCallCached(node1.asNode(), call) or + isUnreachableInCallCached(node2.asNode(), call) + ) + } +} + +private import LocalFlowBigStep + +private module Stage3Param implements MkStage::StageParam { + private module PrevStage = Stage2; + + class Ap = AccessPathFront; + + class ApNil = AccessPathFrontNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathFrontOption; + + ApOption apNone() { result = TAccessPathFrontNone() } + + ApOption apSome(Ap ap) { result = TAccessPathFrontSome(ap) } + + import BooleanCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand2/5; + + predicate flowIntoCall = flowIntoCallNodeCand2/5; + + pragma[nomagic] + private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { + PrevStage::revFlow(node, config) and + clearsContentCached(node.asNode(), c) + } + + pragma[nomagic] + private predicate clearContent(NodeEx node, Content c, Configuration config) { + exists(ContentSet cs | + PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and + c = cs.getAReadContent() and + clearSet(node, cs, pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate clear(NodeEx node, Ap ap, Configuration config) { + clearContent(node, ap.getHead().getContent(), config) + } + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + + pragma[nomagic] + private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + exists(state) and + exists(config) and + not clear(node, ap, config) and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { + // We need to typecheck stores here, since reverse flow through a getter + // might have a different type here compared to inside the getter. + compatibleTypes(ap.getType(), contentType) + } +} + +private module Stage3 implements StageSig { + import MkStage::Stage +} + +/** + * Holds if `argApf` is recorded as the summary context for flow reaching `node` + * and remains relevant for the following pruning stage. + */ +private predicate flowCandSummaryCtx( + NodeEx node, FlowState state, AccessPathFront argApf, Configuration config +) { + exists(AccessPathFront apf | + Stage3::revFlow(node, state, true, _, apf, config) and + Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) + ) +} + +/** + * Holds if a length 2 access path approximation with the head `tc` is expected + * to be expensive. + */ +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(NodeEx n, FlowState state | + Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + or + flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + ) and + accessPathApproxCostLimits(apLimit, tupleLimit) and + apLimit < tails and + tupleLimit < (tails - 1) * nodes and + not tc.forceHighPrecision() + ) +} + +private newtype TAccessPathApprox = + TNil(DataFlowType t) or + TConsNil(TypedContent tc, DataFlowType t) { + Stage3::consCand(tc, TFrontNil(t), _) and + not expensiveLen2unfolding(tc, _) + } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + Stage3::consCand(tc1, TFrontHead(tc2), _) and + len in [2 .. accessPathLimit()] and + not expensiveLen2unfolding(tc1, _) + } or + TCons1(TypedContent tc, int len) { + len in [1 .. accessPathLimit()] and + expensiveLen2unfolding(tc, _) + } + +/** + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence of dereference operations needed to get from the value in the node + * to the tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPathApprox extends TAccessPathApprox { + abstract string toString(); + + abstract TypedContent getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); +} + +private class AccessPathApproxNil extends AccessPathApprox, TNil { + private DataFlowType t; + + AccessPathApproxNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override TypedContent getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override AccessPathApprox pop(TypedContent head) { none() } +} + +abstract private class AccessPathApproxCons extends AccessPathApprox { } + +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; + private DataFlowType t; + + AccessPathApproxConsNil() { this = TConsNil(tc, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override TypedContent getHead() { result = tc } + + override int len() { result = 1 } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } +} + +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; + private int len; + + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } + + override string toString() { + if len = 2 + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc1 } + + override int len() { result = len } + + override DataFlowType getType() { result = tc1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc1) } + + override AccessPathApprox pop(TypedContent head) { + head = tc1 and + ( + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + } +} + +private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 { + private TypedContent tc; + private int len; + + AccessPathApproxCons1() { this = TCons1(tc, len) } + + override string toString() { + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc } + + override int len() { result = len } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { + head = tc and + ( + exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + or + exists(DataFlowType t | + len = 1 and + Stage3::consCand(tc, TFrontNil(t), _) and + result = TNil(t) + ) + ) + } +} + +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } + +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } + +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) + +private class AccessPathApproxOption extends TAccessPathApproxOption { + string toString() { + this = TAccessPathApproxNone() and result = "" + or + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) + } +} + +private module Stage4Param implements MkStage::StageParam { + private module PrevStage = Stage3; + + class Ap = AccessPathApprox; + + class ApNil = AccessPathApproxNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathApproxOption; + + ApOption apNone() { result = TAccessPathApproxNone() } + + ApOption apSome(Ap ap) { result = TAccessPathApproxSome(ap) } + + import Level1CallContext + import LocalCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) + } + + pragma[nomagic] + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config + ) { + exists(FlowState state | + flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow, + Configuration config + ) { + exists(FlowState state | + flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { any() } + + // Type checking is not necessary here as it has already been done in stage 3. + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage4 = MkStage::Stage; + +bindingset[conf, result] +private Configuration unbindConf(Configuration conf) { + exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c)) +} + +pragma[nomagic] +private predicate nodeMayUseSummary0( + NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(AccessPathApprox apa0 | + Stage4::parameterMayFlowThrough(_, c, _, _) and + Stage4::revFlow(n, state, true, _, apa0, config) and + Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and + n.getEnclosingCallable() = c + ) +} + +pragma[nomagic] +private predicate nodeMayUseSummary( + NodeEx n, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(DataFlowCallable c | + Stage4::parameterMayFlowThrough(_, c, apa, config) and + nodeMayUseSummary0(n, c, state, apa, config) + ) +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { + exists(Configuration config | + Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and + Stage4::revFlow(p, state, _, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParamNodeEx p; + private FlowState s; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, s, ap) } + + ParameterPosition getParameterPos() { p.isParameterOf(_, result) } + + ParamNodeEx getParamNode() { result = p } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** + * Gets the number of length 2 access path approximations that correspond to `apa`. + */ +private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) { + exists(TypedContent tc, int len | + tc = apa.getHead() and + len = apa.len() and + result = + strictcount(AccessPathFront apf | + Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), + config) + ) + ) +} + +private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { + result = + strictcount(NodeEx n, FlowState state | + Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) + ) +} + +/** + * Holds if a length 2 access path approximation matching `apa` is expected + * to be expensive. + */ +private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configuration config) { + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = count1to2unfold(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + apLimit < aps and + tupleLimit < (aps - 1) * nodes + ) +} + +private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { + exists(TypedContent head | + apa.pop(head) = result and + Stage4::consCand(head, result, config) + ) +} + +/** + * Holds with `unfold = false` if a precise head-tail representation of `apa` is + * expected to be expensive. Holds with `unfold = true` otherwise. + */ +private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) { + if apa.getHead().forceHighPrecision() + then unfold = true + else + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = countPotentialAps(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true + ) +} + +/** + * Gets the number of `AccessPath`s that correspond to `apa`. + */ +private int countAps(AccessPathApprox apa, Configuration config) { + evalUnfold(apa, false, config) and + result = 1 and + (not apa instanceof AccessPathApproxCons1 or expensiveLen1to2unfolding(apa, config)) + or + evalUnfold(apa, false, config) and + result = count1to2unfold(apa, config) and + not expensiveLen1to2unfolding(apa, config) + or + evalUnfold(apa, true, config) and + result = countPotentialAps(apa, config) +} + +/** + * Gets the number of `AccessPath`s that would correspond to `apa` assuming + * that it is expanded to a precise head-tail representation. + */ +language[monotonicAggregates] +private int countPotentialAps(AccessPathApprox apa, Configuration config) { + apa instanceof AccessPathApproxNil and result = 1 + or + result = strictsum(AccessPathApprox tail | tail = getATail(apa, config) | countAps(tail, config)) +} + +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { + exists(AccessPathApproxCons apa | + not evalUnfold(apa, false, _) and + head = apa.getHead() and + tail.getApprox() = getATail(apa, _) + ) + } or + TAccessPathCons2(TypedContent head1, TypedContent head2, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + not expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head1 = apa.getHead() and + head2 = getATail(apa, _).getHead() + ) + } or + TAccessPathCons1(TypedContent head, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head = apa.getHead() + ) + } + +private newtype TPathNode = + TPathNodeMid( + NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config + ) { + // A PathNode is introduced by a source ... + Stage4::revFlow(node, state, config) and + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, state, cc, sc, ap) and + pragma[only_bind_into](config) = mid.getConfiguration() and + Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) + ) + } or + TPathNodeSink(NodeEx node, FlowState state, Configuration config) { + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + state = sink.getState() and + config = sink.getConfiguration() + ) + } + +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * of dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +private class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + or + result = TCons1(head, this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl(boolean needsSuffix) { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + needsSuffix = false and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl(needsSuffix) + or + exists(TypedContent tc2, TypedContent tc3, int len | tail = TAccessPathCons2(tc2, tc3, len) | + result = head + ", " + tc2 + ", " + tc3 + ", ... (" and len > 2 and needsSuffix = true + or + result = head + ", " + tc2 + ", " + tc3 + "]" and len = 2 and needsSuffix = false + ) + or + exists(TypedContent tc2, int len | tail = TAccessPathCons1(tc2, len) | + result = head + ", " + tc2 + ", ... (" and len > 1 and needsSuffix = true + or + result = head + ", " + tc2 + "]" and len = 1 and needsSuffix = false + ) + } + + override string toString() { + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" + or + result = "[" + this.toStringImpl(false) + } +} + +private class AccessPathCons2 extends AccessPath, TAccessPathCons2 { + private TypedContent head1; + private TypedContent head2; + private int len; + + AccessPathCons2() { this = TAccessPathCons2(head1, head2, len) } + + override TypedContent getHead() { result = head1 } + + override AccessPath getTail() { + Stage4::consCand(head1, result.getApprox(), _) and + result.getHead() = head2 and + result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + + override AccessPathApproxCons getApprox() { + result = TConsCons(head1, head2, len) or + result = TCons1(head1, len) + } + + override int length() { result = len } + + override string toString() { + if len = 2 + then result = "[" + head1.toString() + ", " + head2.toString() + "]" + else + result = "[" + head1.toString() + ", " + head2.toString() + ", ... (" + len.toString() + ")]" + } +} + +private class AccessPathCons1 extends AccessPath, TAccessPathCons1 { + private TypedContent head; + private int len; + + AccessPathCons1() { this = TAccessPathCons1(head, len) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { + Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { result = TCons1(head, len) } + + override int length() { result = len } + + override string toString() { + if len = 1 + then result = "[" + head.toString() + "]" + else result = "[" + head.toString() + ", ... (" + len.toString() + ")]" + } +} + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result } + + /** Gets the `FlowState` of this node. */ + FlowState getState() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getANonHiddenSuccessor() and + reach(this) and + reach(result) + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNodeImpl getASuccessorImpl(); + + private PathNodeImpl getASuccessorIfHidden() { + this.isHidden() and + result = this.getASuccessorImpl() + } + + final PathNodeImpl getANonHiddenSuccessor() { + result = this.getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + abstract NodeEx getNodeEx(); + + predicate isHidden() { + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) + } + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } + + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate directReach(PathNodeImpl n) { + n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor()) +} + +/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ +private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } + +/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNodeImpl n1, PathNode n2) { + n1.getANonHiddenSuccessor() = n2 and directReach(n2) +} + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { + Subpaths::subpaths(arg, par, ret, out) and + reach(arg) and + reach(par) and + reach(ret) and + reach(out) + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + NodeEx node; + FlowState state; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, ap, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbindConf(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = this.getSuccMid() + or + // a final step to a sink + result = this.getSuccMid().projectToSink() + } + + override predicate isSource() { + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + } + + predicate isAtSink() { + sinkNode(node, state, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getState() = state and + result.getConfiguration() = unbindConf(config) + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + NodeEx node; + FlowState state; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, state, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + override Configuration getConfiguration() { result = config } + + override PathNodeImpl getASuccessorImpl() { none() } + + override predicate isSource() { sourceNode(node, state, config) } +} + +private predicate pathNode( + PathNodeMid mid, NodeEx midnode, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, + Configuration conf, LocalCallContext localCC +) { + midnode = mid.getNodeEx() and + state = mid.getState() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + midnode.getEnclosingCallable()) and + ap = mid.getAp() +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +pragma[nomagic] +private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap +) { + exists(NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC | + pathNode(mid, midnode, state0, cc, sc, ap, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, true, _, conf, localCC) + ) + or + exists( + AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC + | + pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + exists(TypedContent tc | pathStoreStep(mid, node, state, ap.pop(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + exists(TypedContent tc | pathReadStep(mid, node, state, ap.push(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, state, _, cc, sc, _, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, state, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, state, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate pathReadStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + tc = ap0.getHead() and + Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, FlowState state, CallContext innercc, AccessPathApprox apa, + Configuration config +) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPathApprox apa, Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, state, innercc, apa, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private NodeEx getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config +) { + result.asNode() = kind.getAnOutNode(call) and + Stage4::revFlow(result, _, apa, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, FlowState state, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, state, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, ParameterPosition ppos, FlowState state, CallContext cc, DataFlowCall call, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(ArgNodeEx arg, ArgumentPosition apos | + pathNode(mid, arg, state, cc, _, ap, config, _) and + arg.asNode().(ArgNode).argumentOf(call, apos) and + apa = ap.getApprox() and + parameterMatch(ppos, apos) + ) +} + +pragma[nomagic] +private predicate parameterCand( + DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config +) { + exists(ParamNodeEx p | + Stage4::revFlow(p, _, apa, config) and + p.isParameterOf(callable, pos) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, AccessPath ap, Configuration config +) { + exists(AccessPathApprox apa | + pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, ap, + pragma[only_bind_into](apa), pragma[only_bind_into](config)) and + callable = resolveCall(call, outercc) and + parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) + ) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +pragma[nomagic] +private predicate pathIntoCallable( + PathNodeMid mid, ParamNodeEx p, FlowState state, CallContext outercc, CallContextCall innercc, + SummaryCtx sc, DataFlowCall call, Configuration config +) { + exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + ( + sc = TSummaryCtxSome(p, state, ap) + or + not exists(TSummaryCtxSome(p, state, ap)) and + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, + AccessPathApprox apa, Configuration config +) { + exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | + pathNode(mid, ret, state, cc, sc, ap, config, _) and + kind = ret.getKind() and + apa = ap.getApprox() and + pos = sc.getParameterPos() and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, state, innercc, sc, ap, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable( + PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, AccessPath ap +) { + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, state, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +private module Subpaths { + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths01( + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + exists(Configuration config | + pathThroughCallable(arg, out, pragma[only_bind_into](sout), _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, _, innercc, sc, _, config) and + paramFlowsThrough(kind, pragma[only_bind_into](sout), innercc, sc, + pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `sout`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths02( + PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and + out.asNode() = kind.getAnOutNode(_) + } + + pragma[nomagic] + private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple. + */ + pragma[nomagic] + private predicate subpaths03( + PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout + ) { + exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | + subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and + pathNode(ret, retnode, sout, innercc, sc, apout, unbindConf(getPathNodeConf(arg)), _) and + kind = retnode.getKind() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, _, n2, _, _, _, _, _) or + store(n1, _, n2, _, _) or + readSet(n1, _, n2, _) + ) + } + + pragma[nomagic] + private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getANonHiddenSuccessor() and + succNode = succ.getNodeEx() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { + exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | + pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and + subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and + not ret.isHidden() and + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() + ) + } + + /** + * Holds if `n` can reach a return node in a summarized subpath that can reach a sink. + */ + predicate retReach(PathNodeImpl n) { + exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) + or + exists(PathNodeImpl mid | + retReach(mid) and + n.getANonHiddenSuccessor() = mid and + not subpaths(_, mid, _, _) + ) + } +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.(PathNodeImpl).getNodeEx().asNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNodeEx().asNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private predicate finalStats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples +) { + fwd = true 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and + tuples = count(PathNode pn) + or + fwd = false 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and + tuples = count(PathNode pn | reach(pn)) +} + +/** + * INTERNAL: Only for debugging. + * + * Calculates per-stage metrics for data flow. + */ +predicate stageStats( + int n, string stage, int nodes, int fields, int conscand, int states, int tuples, + Configuration config +) { + stage = "1 Fwd" and + n = 10 and + Stage1::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "1 Rev" and + n = 15 and + Stage1::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Fwd" and + n = 20 and + Stage2::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Rev" and + n = 25 and + Stage2::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Fwd" and + n = 30 and + Stage3::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Rev" and + n = 35 and + Stage3::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Fwd" and + n = 40 and + Stage4::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Rev" and + n = 45 and + Stage4::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) + or + stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + additionalJumpStateStep(node1, _, node2, _, config) + or + // flow into callable + viableParamArgEx(_, node2, node1) + or + // flow out of a callable + viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) or config.isSource(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private predicate interestingCallableSink(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSink(n) or config.isSink(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSink(mid, config) and callableStep(c, mid, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { + interestingCallableSrc(c, config) or + interestingCallableSink(c, config) + } or + TCallableSrc() or + TCallableSink() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtSink(TCallableSink sink) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, pragma[only_bind_into](config)) and + ce2 = TCallable(c2, pragma[only_bind_into](config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + (config.isSource(n) or config.isSource(n, _)) and + ce2 = TCallable(getNodeEnclosingCallable(n), config) + ) + or + exists(Node n, Configuration config | + ce2 = TCallableSink() and + (config.isSink(n) or config.isSink(n, _)) and + ce1 = TCallable(getNodeEnclosingCallable(n), config) + ) + } + + private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) { + callableExtStepFwd(ce2, ce1) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSinkExt(TCallableExt c) = + shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private int distSink(DataFlowCallable c, Configuration config) { + result = distSinkExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + TypedContent getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private newtype TRevPartialAccessPath = + TRevPartialNil() or + TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `Content`s, but only the first + * element of the list and its length are tracked. + */ + private class RevPartialAccessPath extends TRevPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TRevPartialCons(result, _) } + + int len() { + this = TRevPartialNil() and result = 0 + or + this = TRevPartialCons(_, result) + } + } + + private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil { + override string toString() { result = "" } + } + + private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons { + override string toString() { + exists(Content c, int len | this = TRevPartialCons(c, len) | + if len = 1 + then result = "[" + c.toString() + "]" + else result = "[" + c.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private predicate relevantState(FlowState state) { + sourceNode(_, state, _) or + sinkNode(_, state, _) or + additionalLocalStateStep(_, state, _, _, _) or + additionalLocalStateStep(_, _, _, state, _) or + additionalJumpStateStep(_, state, _, _, _) or + additionalJumpStateStep(_, _, _, state, _) + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParamNodeEx p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TSummaryCtx3 = + TSummaryCtx3None() or + TSummaryCtx3Some(PartialAccessPath ap) + + private newtype TRevSummaryCtx1 = + TRevSummaryCtx1None() or + TRevSummaryCtx1Some(ReturnPosition pos) + + private newtype TRevSummaryCtx2 = + TRevSummaryCtx2None() or + TRevSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TRevSummaryCtx3 = + TRevSummaryCtx3None() or + TRevSummaryCtx3Some(RevPartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeFwd( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = TPartialNil(node.getDataFlowType()) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } or + TPartialPathNodeRev( + NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, TRevSummaryCtx3 sc3, + RevPartialAccessPath ap, Configuration config + ) { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() and + exists(config.explorationLimit()) + or + exists(PartialPathNodeRev mid | + revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and + not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() + ) + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and + if node.asNode() instanceof CastingNode + then compatibleTypes(node.getDataFlowType(), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + 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.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.getNodeEx().projectToNode() = result } + + FlowState getState() { none() } + + private NodeEx getNodeEx() { + result = this.(PartialPathNodeFwd).getNodeEx() or + result = this.(PartialPathNodeRev).getNodeEx() + } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + /** + * Gets the approximate distance to the nearest sink measured in number + * of interprocedural steps. + */ + int getSinkDistance() { + result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | + s = this.(PartialPathNodeFwd).getAp().toString() or + s = this.(PartialPathNodeRev).getAp().toString() + | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">" + } + + /** Holds if this is a source in a forward-flow path. */ + predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() } + + /** Holds if this is a sink in a reverse-flow path. */ + predicate isRevSink() { this.(PartialPathNodeRev).isSink() } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd { + NodeEx node; + FlowState state; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + TSummaryCtx3 sc3; + PartialAccessPath ap; + Configuration config; + + PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, state, cc, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TSummaryCtx3 getSummaryCtx3() { result = sc3 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeFwd getASuccessor() { + partialPathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx1(), result.getSummaryCtx2(), result.getSummaryCtx3(), result.getAp(), + result.getConfiguration()) + } + + predicate isSource() { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap instanceof TPartialNil + } + } + + private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev { + NodeEx node; + FlowState state; + TRevSummaryCtx1 sc1; + TRevSummaryCtx2 sc2; + TRevSummaryCtx3 sc3; + RevPartialAccessPath ap; + Configuration config; + + PartialPathNodeRev() { this = TPartialPathNodeRev(node, state, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + TRevSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TRevSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TRevSummaryCtx3 getSummaryCtx3() { result = sc3 } + + RevPartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeRev getASuccessor() { + revPartialPathStep(result, this.getNodeEx(), this.getState(), this.getSummaryCtx1(), + this.getSummaryCtx2(), this.getSummaryCtx3(), this.getAp(), this.getConfiguration()) + } + + predicate isSink() { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() + } + } + + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalLocalStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsFwd(ap, tc, ap0, config) + ) + or + partialPathIntoCallable(mid, node, state, _, cc, sc1, sc2, sc3, _, ap, config) + or + partialPathOutOfCallable(mid, node, state, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() + or + partialPathThroughCallable(mid, node, state, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + bindingset[result, i] + private int unbindInt(int i) { pragma[only_bind_out](i) = pragma[only_bind_out](result) } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node, + PartialAccessPath ap2 + ) { + exists(NodeEx midNode, DataFlowType contentType | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType, mid.getConfiguration()) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStoreStep(mid, ap1, tc, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc, + Configuration config + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and + ap.getHead() = tc and + pragma[only_bind_into](config) = mid.getConfiguration() and + cc = mid.getCallContext() + ) + } + + private predicate partialPathOutOfCallable0( + PartialPathNodeFwd mid, ReturnPosition pos, FlowState state, CallContext innercc, + PartialAccessPath ap, Configuration config + ) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, state, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, state, cc, ap, config) + | + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodeFwd mid, ParameterPosition ppos, FlowState state, CallContext cc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ArgNode arg, ArgumentPosition apos | + arg = mid.getNodeEx().asNode() and + state = mid.getState() and + cc = mid.getCallContext() and + arg.argumentOf(call, apos) and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, pos, state, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodeFwd mid, ParamNodeEx p, FlowState state, CallContext outercc, + CallContextCall innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ParameterPosition pos, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(state) and + sc3 = TSummaryCtx3Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, FlowState state, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid, RetNodeEx ret | + mid.getNodeEx() = ret and + kind = ret.getKind() and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3 | + partialPathIntoCallable(mid, _, _, cc, innercc, sc1, sc2, sc3, call, _, config) and + paramFlowsThroughInPartialPath(kind, state, innercc, sc1, sc2, sc3, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, state, cc, ap, config) and + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[nomagic] + private predicate revPartialPathStep( + PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, + TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config + ) { + localFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalLocalStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + jumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalJumpStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + revPartialPathReadStep(mid, _, _, node, ap) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(RevPartialAccessPath ap0, Content c | + revPartialPathStoreStep(mid, ap0, c, node, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsRev(ap, c, ap0, config) + ) + or + exists(ParamNodeEx p | + mid.getNodeEx() = p and + viableParamArgEx(_, p, node) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + or + exists(ReturnPosition pos | + revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap, config) and + pos = getReturnPosition(node.asNode()) + ) + or + revPartialPathThroughCallable(mid, node, state, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + pragma[inline] + private predicate revPartialPathReadStep( + PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node, + RevPartialAccessPath ap2 + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + read(node, c, midNode, mid.getConfiguration()) and + ap2.getHead() = c and + ap2.len() = unbindInt(ap1.len() + 1) + ) + } + + pragma[nomagic] + private predicate apConsRev( + RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeRev mid | + revPartialPathReadStep(mid, ap1, c, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathStoreStep( + PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config + ) { + exists(NodeEx midNode, TypedContent tc | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + store(node, tc, midNode, _, config) and + ap.getHead() = c and + config = mid.getConfiguration() and + tc.getContent() = c + ) + } + + pragma[nomagic] + private predicate revPartialPathIntoReturn( + PartialPathNodeRev mid, ReturnPosition pos, FlowState state, TRevSummaryCtx1Some sc1, + TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3, DataFlowCall call, RevPartialAccessPath ap, + Configuration config + ) { + exists(NodeEx out | + mid.getNodeEx() = out and + mid.getState() = state and + viableReturnPosOutEx(call, pos, out) and + sc1 = TRevSummaryCtx1Some(pos) and + sc2 = TRevSummaryCtx2Some(state) and + sc3 = TRevSummaryCtx3Some(ap) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathFlowsThrough( + ArgumentPosition apos, FlowState state, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, + TRevSummaryCtx3Some sc3, RevPartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos | + mid.getNodeEx() = p and + mid.getState() = state and + p.getPosition() = ppos and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable0( + DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, FlowState state, + RevPartialAccessPath ap, Configuration config + ) { + exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3 | + revPartialPathIntoReturn(mid, _, _, sc1, sc2, sc3, call, _, config) and + revPartialPathFlowsThrough(pos, state, sc1, sc2, sc3, ap, config) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable( + PartialPathNodeRev mid, ArgNodeEx node, FlowState state, RevPartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ArgumentPosition pos | + revPartialPathThroughCallable0(call, mid, pos, state, ap, config) and + node.asNode().(ArgNode).argumentOf(call, pos) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + source.isFwdSource() and + node = source.getASuccessor+() +} + +private predicate revPartialFlow( + PartialPathNode node, PartialPathNode sink, Configuration configuration +) { + sink.getConfiguration() = configuration and + sink.isRevSink() and + node.getASuccessor+() = sink +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll new file mode 100644 index 00000000000..468f8640a78 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -0,0 +1,4450 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. This file exists in several identical + * copies, allowing queries to use multiple `Configuration` classes that depend + * on each other without introducing mutual recursion among those configurations. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ```ql + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(Node source) { none() } + + /** + * Holds if `source` is a relevant data flow source with the given initial + * `state`. + */ + predicate isSource(Node source, FlowState state) { none() } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(Node sink) { none() } + + /** + * Holds if `sink` is a relevant data flow sink accepting `state`. + */ + predicate isSink(Node source, FlowState state) { none() } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** + * Holds if data flow through `node` is prohibited when the flow state is + * `state`. + */ + predicate isBarrier(Node node, FlowState state) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited when + * the flow state is `state` + */ + deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) { + none() + } + + /** + * Holds if an arbitrary number of implicit read steps of content `c` may be + * taken at `node`. + */ + predicate allowImplicitRead(Node node, ContentSet c) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` + * measured in approximate number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } + + /** + * Holds if there is a partial data flow path from `node` to `sink`. The + * approximate distance between `node` and the closest sink is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards source definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sinks is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + * + * Note that reverse flow has slightly lower precision than the corresponding + * forward flow, as reverse flow disregards type pruning among other features. + */ + final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) { + revPartialFlow(node, sink, this) and + dist = node.getSinkDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSource(n, _)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n | this.isSink(n, _)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0 + or + super.hasFlow(source, sink) + } +} + +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 class ArgNodeEx extends NodeEx { + ArgNodeEx() { this.asNode() instanceof ArgNode } +} + +private class ParamNodeEx extends NodeEx { + ParamNodeEx() { this.asNode() instanceof ParamNode } + + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + this.asNode().(ParamNode).isParameterOf(c, pos) + } + + ParameterPosition getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } +} + +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) + | + config.isSource(n) or config.isSource(n, _) + ) +} + +private predicate outBarrier(NodeEx node, Configuration config) { + exists(Node n | + node.asNode() = n and + config.isBarrierOut(n) + | + config.isSink(n) or config.isSink(n, _) + ) +} + +/** A bridge class to access the deprecated `isBarrierGuard`. */ +private class BarrierGuardGuardedNodeBridge extends Unit { + abstract predicate guardedNode(Node n, Configuration config); + + abstract predicate guardedNode(Node n, FlowState state, Configuration config); +} + +private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge { + deprecated override predicate guardedNode(Node n, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g) and + n = g.getAGuardedNode() + ) + } + + deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g, state) and + n = g.getAGuardedNode() + ) + } +} + +pragma[nomagic] +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) and + not config.isSource(n, _) + or + config.isBarrierOut(n) and + not config.isSink(n) and + not config.isSink(n, _) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config) + ) +} + +pragma[nomagic] +private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) { + exists(Node n | node.asNode() = n | + config.isBarrier(n, state) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config) + ) +} + +pragma[nomagic] +private predicate sourceNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSource(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSource(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +pragma[nomagic] +private predicate sinkNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSink(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSink(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +/** Provides the relevant barriers for a step from `node1` to `node2`. */ +pragma[inline] +private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) { + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.asNode() = n and + node2.isImplicitReadNode(n, false) and + not fullBarrier(node1, config) + ) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.isImplicitReadNode(n, true) and + node2.asNode() = n and + not fullBarrier(node2, config) + ) +} + +private predicate additionalLocalStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) + ) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate additionalJumpStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +pragma[nomagic] +private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and + stepFilter(node1, node2, config) + or + exists(Node n | + node2.isImplicitReadNode(n, true) and + node1.isImplicitReadNode(n, _) and + config.allowImplicitRead(n, c) + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { + exists(ContentSet cs | + readSet(node1, cs, node2, config) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate clearsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + clearsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + +pragma[nomagic] +private predicate store( + NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config +) { + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and + read(_, tc.getContent(), _, config) and + stepFilter(node1, node2, 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()) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private module Stage1 implements StageSig { + class ApApprox = Unit; + + class Ap = Unit; + + class ApOption = Unit; + + class Cc = boolean; + + /* Begin: Stage 1 logic. */ + /** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `cc` records whether the node is reached through an + * argument in a call. + */ + predicate fwdFlow(NodeEx node, Cc cc, Configuration config) { + sourceNode(node, _, config) and + if hasSourceCallCtx(config) then cc = true else cc = false + or + exists(NodeEx mid | fwdFlow(mid, cc, config) | + localFlowStep(mid, node, config) or + additionalLocalFlowStep(mid, node, config) or + additionalLocalStateStep(mid, _, node, _, config) + ) + or + exists(NodeEx mid | fwdFlow(mid, _, config) and cc = false | + jumpStep(mid, node, config) or + additionalJumpStep(mid, node, config) or + additionalJumpStateStep(mid, _, node, _, config) + ) + or + // store + exists(NodeEx mid | + useFieldFlow(config) and + fwdFlow(mid, cc, config) and + store(mid, _, node, _, config) + ) + or + // read + exists(ContentSet c | + fwdFlowReadSet(c, node, cc, config) and + fwdFlowConsCandSet(c, _, config) + ) + or + // flow into a callable + exists(NodeEx arg | + fwdFlow(arg, _, config) and + viableParamArgEx(_, node, arg) and + cc = true and + not fullBarrier(node, config) + ) + or + // flow out of a callable + exists(DataFlowCall call | + fwdFlowOut(call, node, false, config) and + cc = false + or + fwdFlowOutFromArg(call, node, config) and + fwdFlowIsEntered(call, cc, config) + ) + } + + private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) } + + pragma[nomagic] + private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) { + exists(NodeEx mid | + fwdFlow(mid, cc, config) and + readSet(mid, c, node, config) + ) + } + + /** + * Holds if `c` is the target of a store in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, TypedContent tc | + not fullBarrier(node, config) and + useFieldFlow(config) and + fwdFlow(mid, _, config) and + store(mid, tc, node, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `cs` may be interpreted in a read as the target of some store + * into `c`, in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) { + fwdFlowConsCand(c, config) and + c = cs.getAReadContent() + } + + pragma[nomagic] + private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) { + exists(RetNodeEx ret | + fwdFlow(ret, cc, config) and + ret.getReturnPosition() = pos + ) + } + + pragma[nomagic] + private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) { + exists(ReturnPosition pos | + fwdFlowReturnPosition(pos, cc, config) and + viableReturnPosOutEx(call, pos, out) and + not fullBarrier(out, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) { + fwdFlowOut(call, out, true, config) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { + exists(ArgNodeEx arg | + fwdFlow(arg, cc, config) and + viableParamArgEx(call, _, arg) + ) + } + + private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1 | + additionalLocalStateStep(node1, state1, _, state2, config) or + additionalJumpStateStep(node1, state1, _, state2, config) + | + fwdFlow(node1, config) + ) + } + + private predicate fwdFlowState(FlowState state, Configuration config) { + sourceNode(_, state, config) + or + exists(FlowState state0 | + fwdFlowState(state0, config) and + stateStepFwd(state0, state, config) + ) + } + + /** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ + pragma[nomagic] + predicate revFlow(NodeEx node, boolean toReturn, Configuration config) { + revFlow0(node, toReturn, config) and + fwdFlow(node, config) + } + + pragma[nomagic] + private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { + exists(FlowState state | + fwdFlow(node, pragma[only_bind_into](config)) and + sinkNode(node, state, config) and + fwdFlowState(state, pragma[only_bind_into](config)) and + if hasSinkCallCtx(config) then toReturn = true else toReturn = false + ) + or + exists(NodeEx mid | revFlow(mid, toReturn, config) | + localFlowStep(node, mid, config) or + additionalLocalFlowStep(node, mid, config) or + additionalLocalStateStep(node, _, mid, _, config) + ) + or + exists(NodeEx mid | revFlow(mid, _, config) and toReturn = false | + jumpStep(node, mid, config) or + additionalJumpStep(node, mid, config) or + additionalJumpStateStep(node, _, mid, _, config) + ) + or + // store + exists(Content c | + revFlowStore(c, node, toReturn, config) and + revFlowConsCand(c, config) + ) + or + // read + exists(NodeEx mid, ContentSet c | + readSet(node, c, mid, config) and + fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and + revFlow(mid, toReturn, pragma[only_bind_into](config)) + ) + or + // flow into a callable + exists(DataFlowCall call | + revFlowIn(call, node, false, config) and + toReturn = false + or + revFlowInToReturn(call, node, config) and + revFlowIsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + revFlowOut(pos, config) and + node.(RetNodeEx).getReturnPosition() = pos and + toReturn = true + ) + } + + /** + * Holds if `c` is the target of a read in the flow covered by `revFlow`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, ContentSet cs | + fwdFlow(node, pragma[only_bind_into](config)) and + readSet(node, cs, mid, config) and + fwdFlowConsCandSet(cs, 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, 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, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `c` is the target of both a read and a store in the flow covered + * by `revFlow`. + */ + pragma[nomagic] + predicate revFlowIsReadAndStored(Content c, Configuration conf) { + revFlowConsCand(c, conf) and + revFlowStore(c, _, _, conf) + } + + pragma[nomagic] + predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config + ) { + fwdFlowReturnPosition(pos, _, config) and + viableReturnPosOutEx(call, pos, out) + } + + pragma[nomagic] + private predicate revFlowOut(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, NodeEx out | + revFlow(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) + } + + pragma[nomagic] + predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config + ) { + viableParamArgEx(call, p, arg) and + fwdFlow(arg, config) + } + + pragma[nomagic] + 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, ArgNodeEx arg, Configuration config) { + revFlowIn(call, arg, true, config) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(NodeEx out | + revFlow(out, toReturn, config) and + fwdFlowOutFromArg(call, out, config) + ) + } + + private predicate stateStepRev(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + additionalLocalStateStep(node1, state1, node2, state2, config) or + additionalJumpStateStep(node1, state1, node2, state2, config) + | + revFlow(node1, _, pragma[only_bind_into](config)) and + revFlow(node2, _, pragma[only_bind_into](config)) and + fwdFlowState(state1, pragma[only_bind_into](config)) and + fwdFlowState(state2, pragma[only_bind_into](config)) + ) + } + + predicate revFlowState(FlowState state, Configuration config) { + exists(NodeEx node | + sinkNode(node, state, config) and + revFlow(node, _, pragma[only_bind_into](config)) and + fwdFlowState(state, pragma[only_bind_into](config)) + ) + or + exists(FlowState state0 | + revFlowState(state0, config) and + stateStepRev(state, state0, config) + ) + } + + pragma[nomagic] + predicate storeStepCand( + 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, config) and + c = tc.getContent() and + exists(ap1) + ) + } + + pragma[nomagic] + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + read(n1, c, n2, pragma[only_bind_into](config)) and + revFlow(n2, pragma[only_bind_into](config)) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, _, pragma[only_bind_into](config)) and + exists(state) and + exists(ap) + } + + private predicate throughFlowNodeCand(NodeEx node, Configuration config) { + revFlow(node, true, config) and + fwdFlow(node, true, config) and + not inBarrier(node, config) and + not outBarrier(node, config) + } + + /** Holds if flow may return from `callable`. */ + pragma[nomagic] + private predicate returnFlowCallableNodeCand( + DataFlowCallable callable, ReturnKindExt kind, Configuration config + ) { + exists(RetNodeEx ret | + throughFlowNodeCand(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) + } + + /** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ + pragma[nomagic] + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand(p, config) and + returnFlowCallableNodeCand(c, kind, config) and + p.getEnclosingCallable() = c and + exists(ap) and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists(ArgNodeEx arg, boolean toReturn | + revFlow(arg, toReturn, config) and + revFlowInToReturn(call, arg, config) and + revFlowIsReturned(call, toReturn, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true and + nodes = count(NodeEx node | fwdFlow(node, config)) and + fields = count(Content f0 | fwdFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | fwdFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config)) + or + fwd = false and + nodes = count(NodeEx node | revFlow(node, _, config)) and + fields = count(Content f0 | revFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | revFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | revFlow(n, b, config)) + } + /* End: Stage 1 logic. */ +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) { + Stage1::revFlow(node2, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +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, NodeEx out, Configuration config +) { + Stage1::revFlow(out, config) and + Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config +) { + viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and + Stage1::revFlow(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config +) { + Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and + Stage1::revFlow(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + Stage1::revFlow(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(NodeEx n1, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(NodeEx n2, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +private signature module StageSig { + class Ap; + + predicate revFlow(NodeEx node, Configuration config); + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); + + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); + + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ); + + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config); +} + +private module MkStage { + class ApApprox = PrevStage::Ap; + + signature module StageParam { + class Ap; + + class ApNil extends Ap; + + bindingset[result, ap] + ApApprox getApprox(Ap ap); + + ApNil getApNil(NodeEx node); + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail); + + Content getHeadContent(Ap ap); + + class ApOption; + + ApOption apNone(); + + ApOption apSome(Ap ap); + + class Cc; + + class CcCall extends Cc; + + // TODO: member predicate on CcCall + predicate matchesCall(CcCall cc, DataFlowCall call); + + class CcNoCall extends Cc; + + Cc ccNone(); + + CcCall ccSomeCall(); + + class LocalCc; + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc); + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc); + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc); + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ); + + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config + ); + + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config + ); + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config); + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType); + } + + module Stage implements StageSig { + import Param + + /* Begin: Stage logic. */ + bindingset[result, apa] + private ApApprox unbindApa(ApApprox apa) { + pragma[only_bind_out](apa) = pragma[only_bind_out](result) + } + + pragma[nomagic] + private predicate flowThroughOutOfCall( + DataFlowCall call, CcCall ccc, 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(_, ret.getEnclosingCallable(), _, + pragma[only_bind_into](config)) and + matchesCall(ccc, call) + } + + /** + * Holds if `node` is reachable with access path `ap` from a source in the + * configuration `config`. + * + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ + pragma[nomagic] + predicate fwdFlow( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + fwdFlow0(node, state, cc, argAp, ap, config) and + PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and + filter(node, state, ap, config) + } + + pragma[nomagic] + private predicate fwdFlow0( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + sourceNode(node, state, config) and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and + argAp = apNone() and + ap = getApNil(node) + or + exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | + fwdFlow(mid, state0, cc, argAp, ap0, config) and + localCc = getLocalCc(mid, cc) + | + localStep(mid, state0, node, state, true, _, config, localCc) and + ap = ap0 + or + localStep(mid, state0, node, state, false, ap, config, localCc) and + ap0 instanceof ApNil + ) + or + exists(NodeEx mid | + fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + jumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() + ) + or + exists(NodeEx mid, ApNil nil | + fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStateStep(mid, state0, node, state, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + // store + exists(TypedContent tc, Ap ap0 | + fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and + ap = apCons(tc, ap0) + ) + or + // read + exists(Ap ap0, Content c | + fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and + fwdFlowConsCand(ap0, c, ap, config) + ) + or + // flow into a callable + exists(ApApprox apa | + fwdFlowIn(_, node, state, _, cc, _, ap, config) and + apa = getApprox(ap) and + if PrevStage::parameterMayFlowThrough(node, _, apa, config) + then argAp = apSome(ap) + else argAp = apNone() + ) + or + // flow out of a callable + fwdFlowOutNotFromArg(node, state, cc, argAp, ap, config) + or + exists(DataFlowCall call, Ap argAp0 | + fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and + fwdFlowIsEntered(call, cc, argAp, argAp0, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowStore( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + exists(DataFlowType contentType | + fwdFlow(node1, state, cc, argAp, ap1, config) and + PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and + typecheckStore(ap1, contentType) + ) + } + + /** + * Holds if forward flow with access path `tail` reaches a store of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(TypedContent tc | + fwdFlowStore(_, tail, tc, _, _, _, _, config) and + tc.getContent() = c and + cons = apCons(tc, tail) + ) + } + + pragma[nomagic] + private predicate fwdFlowRead( + Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + fwdFlow(node1, state, cc, argAp, ap, config) and + PrevStage::readStepCand(node1, c, node2, config) and + getHeadContent(ap) = c + } + + pragma[nomagic] + private predicate fwdFlowIn( + DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, + Ap ap, Configuration config + ) { + exists(ArgNodeEx arg, boolean allowsFieldFlow | + fwdFlow(arg, state, outercc, argAp, ap, config) and + flowIntoCall(call, arg, p, allowsFieldFlow, config) and + innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutNotFromArg( + NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config + ) { + exists( + DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, + DataFlowCallable inner + | + fwdFlow(ret, state, innercc, argAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + inner = ret.getEnclosingCallable() and + ccOut = getCallContextReturn(inner, call, innercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg( + DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc | + fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and + flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow` + * and data might flow through the target callable and back out at `call`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered( + DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p | + fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and + PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) + ) + } + + pragma[nomagic] + private predicate storeStepFwd( + 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( + 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, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, + pragma[only_bind_into](config)) and + fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate flowThroughIntoCall( + 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 + PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and + callMayFlowThroughFwd(call, pragma[only_bind_into](config)) + } + + pragma[nomagic] + private predicate returnNodeMayFlowThrough( + RetNodeEx ret, FlowState state, Ap ap, Configuration config + ) { + fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config) + } + + /** + * Holds if `node` with access path `ap` is part of a path from a source to a + * sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from the + * enclosing callable in order to reach a sink, and if so, `returnAp` records + * the access path of the returned value. + */ + pragma[nomagic] + predicate revFlow( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + revFlow0(node, state, toReturn, returnAp, ap, config) and + fwdFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + private predicate revFlow0( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + fwdFlow(node, state, _, _, ap, config) and + sinkNode(node, state, config) and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and + returnAp = apNone() and + ap instanceof ApNil + or + exists(NodeEx mid, FlowState state0 | + localStep(node, state, mid, state0, true, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, ap, config) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and + ap instanceof ApNil + ) + or + exists(NodeEx mid | + jumpStep(node, mid, config) and + revFlow(mid, state, _, _, ap, config) and + toReturn = false and + returnAp = apNone() + ) + or + 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), state, _, _, nil, pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and + additionalJumpStateStep(node, state, mid, state0, config) and + revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, + pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + // store + exists(Ap ap0, Content c | + revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and + revFlowConsCand(ap0, c, ap, config) + ) + or + // read + exists(NodeEx mid, Ap ap0 | + revFlow(mid, state, toReturn, returnAp, ap0, config) and + readStepFwd(node, ap, _, mid, ap0, config) + ) + or + // flow into a callable + revFlowInNotToReturn(node, state, returnAp, ap, config) and + toReturn = false + or + exists(DataFlowCall call, Ap returnAp0 | + revFlowInToReturn(call, node, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + or + // flow out of a callable + revFlowOut(_, node, state, _, _, ap, config) and + toReturn = true and + if returnNodeMayFlowThrough(node, state, ap, config) + then returnAp = apSome(ap) + else returnAp = apNone() + } + + pragma[nomagic] + private predicate revFlowStore( + Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, + boolean toReturn, ApOption returnAp, Configuration config + ) { + revFlow(mid, state, toReturn, returnAp, ap0, config) and + storeStepFwd(node, ap, tc, mid, ap0, config) and + tc.getContent() = c + } + + /** + * Holds if reverse flow with access path `tail` reaches a read of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(NodeEx mid, Ap tail0 | + revFlow(mid, _, _, _, tail, config) and + tail = pragma[only_bind_into](tail0) and + readStepFwd(_, cons, c, mid, tail0, config) + ) + } + + pragma[nomagic] + private predicate revFlowOut( + DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, + Configuration config + ) { + exists(NodeEx out, boolean allowsFieldFlow | + revFlow(out, state, toReturn, returnAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInNotToReturn( + ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, false, returnAp, ap, config) and + flowIntoCall(_, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInToReturn( + DataFlowCall call, ArgNodeEx arg, FlowState state, Ap returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, true, apSome(returnAp), ap, config) and + flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned( + DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, FlowState state, CcCall ccc | + revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and + fwdFlow(ret, state, ccc, apSome(_), ap, config) and + matchesCall(ccc, call) + ) + } + + pragma[nomagic] + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ) { + exists(Ap ap2, Content c | + PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and + revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and + revFlowConsCand(ap2, c, ap1, 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 + revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _, _, + pragma[only_bind_into](config)) + ) + } + + predicate revFlow(NodeEx node, FlowState state, Configuration config) { + revFlow(node, state, _, _, _, config) + } + + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, ap, config) + } + + private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepFwd(_, ap, tc, _, _, config) + } + + private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepCand(_, ap, tc, _, _, config) + } + + private predicate validAp(Ap ap, Configuration config) { + revFlow(_, _, _, _, ap, config) and ap instanceof ApNil + or + exists(TypedContent head, Ap tail | + consCand(head, tail, config) and + ap = apCons(head, tail) + ) + } + + predicate consCand(TypedContent tc, Ap ap, Configuration config) { + revConsCand(tc, ap, config) and + validAp(ap, config) + } + + pragma[noinline] + private predicate parameterFlow( + ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config + ) { + revFlow(p, _, true, apSome(ap0), ap, config) and + c = p.getEnclosingCallable() + } + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | + parameterFlow(p, ap, ap0, c, config) and + c = ret.getEnclosingCallable() and + revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), + pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and + fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and + kind = ret.getKind() and + p.getPosition() = pos and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists( + Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap + | + revFlow(arg, state, toReturn, returnAp, ap, config) and + revFlowInToReturn(call, arg, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true 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 + states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(n, state, cc, argAp, ap, config) + ) + or + fwd = false 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 + states = count(FlowState state | revFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | + revFlow(n, state, b, retAp, ap, config) + ) + } + /* End: Stage logic. */ + } +} + +private module BooleanCallContext { + class Cc extends boolean { + Cc() { this in [true, false] } + } + + class CcCall extends Cc { + CcCall() { this = true } + } + + /** Holds if the call context may be `call`. */ + predicate matchesCall(CcCall cc, DataFlowCall call) { any() } + + class CcNoCall extends Cc { + CcNoCall() { this = false } + } + + Cc ccNone() { result = false } + + CcCall ccSomeCall() { result = true } + + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } +} + +private module Level1CallContext { + class Cc = CallContext; + + class CcCall = CallContextCall; + + pragma[inline] + predicate matchesCall(CcCall cc, DataFlowCall call) { cc.matchesCall(call) } + + class CcNoCall = CallContextNoCall; + + Cc ccNone() { result instanceof CallContextAny } + + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + + module NoLocalCallContext { + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } + } + + module LocalCallContext { + class LocalCc = LocalCallContext; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { + result = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + node.getEnclosingCallable()) + } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall() + } + } + + bindingset[call, c, innercc] + 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() + } +} + +private module Stage2Param implements MkStage::StageParam { + private module PrevStage = Stage1; + + class Ap extends boolean { + Ap() { this in [true, false] } + } + + class ApNil extends Ap { + ApNil() { this = false } + } + + bindingset[result, ap] + PrevStage::Ap getApprox(Ap ap) { any() } + + ApNil getApNil(NodeEx node) { Stage1::revFlow(node, _) and exists(result) } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) } + + pragma[inline] + Content getHeadContent(Ap ap) { exists(result) and ap = true } + + class ApOption = BooleanOption; + + ApOption apNone() { result = TBooleanNone() } + + ApOption apSome(Ap ap) { result = TBooleanSome(ap) } + + import Level1CallContext + import NoLocalCallContext + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + ( + preservesValue = true and + localFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalStateStep(node1, state1, node2, state2, config) + ) and + exists(ap) and + exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand1/5; + + predicate flowIntoCall = flowIntoCallNodeCand1/5; + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + PrevStage::revFlowState(state, pragma[only_bind_into](config)) and + exists(ap) and + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage2 implements StageSig { + import MkStage::Stage +} + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +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 NodeEx { + FlowCheckNode() { + castNode(this.asNode()) or + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) + } + } + + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) { + Stage2::revFlow(node, state, config) and + ( + sourceNode(node, state, config) + or + jumpStep(_, node, config) + or + additionalJumpStep(_, node, config) + or + additionalJumpStateStep(_, _, node, state, config) + or + node instanceof ParamNodeEx + or + node.asNode() instanceof OutNodeExt + or + Stage2::storeStepCand(_, _, _, node, _, config) + or + Stage2::readStepCand(_, _, node, config) + or + node instanceof FlowCheckNode + or + exists(FlowState s | + additionalLocalStateStep(_, s, node, state, config) and + s != state + ) + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(NodeEx node, FlowState state, Configuration config) { + exists(NodeEx next | Stage2::revFlow(next, state, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + Stage2::storeStepCand(node, _, _, next, _, config) or + Stage2::readStepCand(node, _, next, config) + ) + or + exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) | + additionalJumpStateStep(node, state, next, s, config) + or + additionalLocalStateStep(node, state, next, s, config) and + s != state + ) + or + Stage2::revFlow(node, state, config) and + node instanceof FlowCheckNode + or + sinkNode(node, state, config) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, Configuration config + ) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 and + Stage2::revFlow(node1, pragma[only_bind_into](state1), false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, pragma[only_bind_into](state2), false, + pragma[only_bind_into](config)) + or + additionalLocalStateStep(node1, state1, node2, state2, config) and + Stage2::revFlow(node1, state1, false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, state2, false, pragma[only_bind_into](config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t, + Configuration config, LocalCallContext cc + ) { + not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = node1.getDataFlowType() and // irrelevant dummy value + Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config)) + or + additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and + preservesValue = false and + t = node2.getDataFlowType() + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) + or + exists(NodeEx mid | + localFlowStepPlus(node1, pragma[only_bind_into](state), 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](state), pragma[only_bind_into](config)) + ) + or + exists(NodeEx mid | + localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and + additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and + not mid instanceof FlowCheckNode and + preservesValue = false and + t = node2.getDataFlowType() + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + AccessPathFrontNil apf, Configuration config, LocalCallContext callContext + ) { + localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, state1, config) and + state1 = state2 + or + additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and + state1 != state2 and + preservesValue = false and + apf = TFrontNil(node2.getDataFlowType()) and + callContext.relevantFor(node1.getEnclosingCallable()) and + not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | + isUnreachableInCallCached(node1.asNode(), call) or + isUnreachableInCallCached(node2.asNode(), call) + ) + } +} + +private import LocalFlowBigStep + +private module Stage3Param implements MkStage::StageParam { + private module PrevStage = Stage2; + + class Ap = AccessPathFront; + + class ApNil = AccessPathFrontNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathFrontOption; + + ApOption apNone() { result = TAccessPathFrontNone() } + + ApOption apSome(Ap ap) { result = TAccessPathFrontSome(ap) } + + import BooleanCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand2/5; + + predicate flowIntoCall = flowIntoCallNodeCand2/5; + + pragma[nomagic] + private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { + PrevStage::revFlow(node, config) and + clearsContentCached(node.asNode(), c) + } + + pragma[nomagic] + private predicate clearContent(NodeEx node, Content c, Configuration config) { + exists(ContentSet cs | + PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and + c = cs.getAReadContent() and + clearSet(node, cs, pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate clear(NodeEx node, Ap ap, Configuration config) { + clearContent(node, ap.getHead().getContent(), config) + } + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + + pragma[nomagic] + private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + exists(state) and + exists(config) and + not clear(node, ap, config) and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { + // We need to typecheck stores here, since reverse flow through a getter + // might have a different type here compared to inside the getter. + compatibleTypes(ap.getType(), contentType) + } +} + +private module Stage3 implements StageSig { + import MkStage::Stage +} + +/** + * Holds if `argApf` is recorded as the summary context for flow reaching `node` + * and remains relevant for the following pruning stage. + */ +private predicate flowCandSummaryCtx( + NodeEx node, FlowState state, AccessPathFront argApf, Configuration config +) { + exists(AccessPathFront apf | + Stage3::revFlow(node, state, true, _, apf, config) and + Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) + ) +} + +/** + * Holds if a length 2 access path approximation with the head `tc` is expected + * to be expensive. + */ +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(NodeEx n, FlowState state | + Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + or + flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + ) and + accessPathApproxCostLimits(apLimit, tupleLimit) and + apLimit < tails and + tupleLimit < (tails - 1) * nodes and + not tc.forceHighPrecision() + ) +} + +private newtype TAccessPathApprox = + TNil(DataFlowType t) or + TConsNil(TypedContent tc, DataFlowType t) { + Stage3::consCand(tc, TFrontNil(t), _) and + not expensiveLen2unfolding(tc, _) + } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + Stage3::consCand(tc1, TFrontHead(tc2), _) and + len in [2 .. accessPathLimit()] and + not expensiveLen2unfolding(tc1, _) + } or + TCons1(TypedContent tc, int len) { + len in [1 .. accessPathLimit()] and + expensiveLen2unfolding(tc, _) + } + +/** + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence of dereference operations needed to get from the value in the node + * to the tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPathApprox extends TAccessPathApprox { + abstract string toString(); + + abstract TypedContent getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); +} + +private class AccessPathApproxNil extends AccessPathApprox, TNil { + private DataFlowType t; + + AccessPathApproxNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override TypedContent getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override AccessPathApprox pop(TypedContent head) { none() } +} + +abstract private class AccessPathApproxCons extends AccessPathApprox { } + +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; + private DataFlowType t; + + AccessPathApproxConsNil() { this = TConsNil(tc, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override TypedContent getHead() { result = tc } + + override int len() { result = 1 } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } +} + +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; + private int len; + + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } + + override string toString() { + if len = 2 + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc1 } + + override int len() { result = len } + + override DataFlowType getType() { result = tc1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc1) } + + override AccessPathApprox pop(TypedContent head) { + head = tc1 and + ( + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + } +} + +private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 { + private TypedContent tc; + private int len; + + AccessPathApproxCons1() { this = TCons1(tc, len) } + + override string toString() { + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc } + + override int len() { result = len } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { + head = tc and + ( + exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + or + exists(DataFlowType t | + len = 1 and + Stage3::consCand(tc, TFrontNil(t), _) and + result = TNil(t) + ) + ) + } +} + +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } + +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } + +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) + +private class AccessPathApproxOption extends TAccessPathApproxOption { + string toString() { + this = TAccessPathApproxNone() and result = "" + or + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) + } +} + +private module Stage4Param implements MkStage::StageParam { + private module PrevStage = Stage3; + + class Ap = AccessPathApprox; + + class ApNil = AccessPathApproxNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathApproxOption; + + ApOption apNone() { result = TAccessPathApproxNone() } + + ApOption apSome(Ap ap) { result = TAccessPathApproxSome(ap) } + + import Level1CallContext + import LocalCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) + } + + pragma[nomagic] + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config + ) { + exists(FlowState state | + flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow, + Configuration config + ) { + exists(FlowState state | + flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { any() } + + // Type checking is not necessary here as it has already been done in stage 3. + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage4 = MkStage::Stage; + +bindingset[conf, result] +private Configuration unbindConf(Configuration conf) { + exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c)) +} + +pragma[nomagic] +private predicate nodeMayUseSummary0( + NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(AccessPathApprox apa0 | + Stage4::parameterMayFlowThrough(_, c, _, _) and + Stage4::revFlow(n, state, true, _, apa0, config) and + Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and + n.getEnclosingCallable() = c + ) +} + +pragma[nomagic] +private predicate nodeMayUseSummary( + NodeEx n, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(DataFlowCallable c | + Stage4::parameterMayFlowThrough(_, c, apa, config) and + nodeMayUseSummary0(n, c, state, apa, config) + ) +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { + exists(Configuration config | + Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and + Stage4::revFlow(p, state, _, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParamNodeEx p; + private FlowState s; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, s, ap) } + + ParameterPosition getParameterPos() { p.isParameterOf(_, result) } + + ParamNodeEx getParamNode() { result = p } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** + * Gets the number of length 2 access path approximations that correspond to `apa`. + */ +private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) { + exists(TypedContent tc, int len | + tc = apa.getHead() and + len = apa.len() and + result = + strictcount(AccessPathFront apf | + Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), + config) + ) + ) +} + +private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { + result = + strictcount(NodeEx n, FlowState state | + Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) + ) +} + +/** + * Holds if a length 2 access path approximation matching `apa` is expected + * to be expensive. + */ +private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configuration config) { + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = count1to2unfold(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + apLimit < aps and + tupleLimit < (aps - 1) * nodes + ) +} + +private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { + exists(TypedContent head | + apa.pop(head) = result and + Stage4::consCand(head, result, config) + ) +} + +/** + * Holds with `unfold = false` if a precise head-tail representation of `apa` is + * expected to be expensive. Holds with `unfold = true` otherwise. + */ +private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) { + if apa.getHead().forceHighPrecision() + then unfold = true + else + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = countPotentialAps(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true + ) +} + +/** + * Gets the number of `AccessPath`s that correspond to `apa`. + */ +private int countAps(AccessPathApprox apa, Configuration config) { + evalUnfold(apa, false, config) and + result = 1 and + (not apa instanceof AccessPathApproxCons1 or expensiveLen1to2unfolding(apa, config)) + or + evalUnfold(apa, false, config) and + result = count1to2unfold(apa, config) and + not expensiveLen1to2unfolding(apa, config) + or + evalUnfold(apa, true, config) and + result = countPotentialAps(apa, config) +} + +/** + * Gets the number of `AccessPath`s that would correspond to `apa` assuming + * that it is expanded to a precise head-tail representation. + */ +language[monotonicAggregates] +private int countPotentialAps(AccessPathApprox apa, Configuration config) { + apa instanceof AccessPathApproxNil and result = 1 + or + result = strictsum(AccessPathApprox tail | tail = getATail(apa, config) | countAps(tail, config)) +} + +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { + exists(AccessPathApproxCons apa | + not evalUnfold(apa, false, _) and + head = apa.getHead() and + tail.getApprox() = getATail(apa, _) + ) + } or + TAccessPathCons2(TypedContent head1, TypedContent head2, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + not expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head1 = apa.getHead() and + head2 = getATail(apa, _).getHead() + ) + } or + TAccessPathCons1(TypedContent head, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head = apa.getHead() + ) + } + +private newtype TPathNode = + TPathNodeMid( + NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config + ) { + // A PathNode is introduced by a source ... + Stage4::revFlow(node, state, config) and + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, state, cc, sc, ap) and + pragma[only_bind_into](config) = mid.getConfiguration() and + Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) + ) + } or + TPathNodeSink(NodeEx node, FlowState state, Configuration config) { + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + state = sink.getState() and + config = sink.getConfiguration() + ) + } + +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * of dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +private class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + or + result = TCons1(head, this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl(boolean needsSuffix) { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + needsSuffix = false and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl(needsSuffix) + or + exists(TypedContent tc2, TypedContent tc3, int len | tail = TAccessPathCons2(tc2, tc3, len) | + result = head + ", " + tc2 + ", " + tc3 + ", ... (" and len > 2 and needsSuffix = true + or + result = head + ", " + tc2 + ", " + tc3 + "]" and len = 2 and needsSuffix = false + ) + or + exists(TypedContent tc2, int len | tail = TAccessPathCons1(tc2, len) | + result = head + ", " + tc2 + ", ... (" and len > 1 and needsSuffix = true + or + result = head + ", " + tc2 + "]" and len = 1 and needsSuffix = false + ) + } + + override string toString() { + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" + or + result = "[" + this.toStringImpl(false) + } +} + +private class AccessPathCons2 extends AccessPath, TAccessPathCons2 { + private TypedContent head1; + private TypedContent head2; + private int len; + + AccessPathCons2() { this = TAccessPathCons2(head1, head2, len) } + + override TypedContent getHead() { result = head1 } + + override AccessPath getTail() { + Stage4::consCand(head1, result.getApprox(), _) and + result.getHead() = head2 and + result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + + override AccessPathApproxCons getApprox() { + result = TConsCons(head1, head2, len) or + result = TCons1(head1, len) + } + + override int length() { result = len } + + override string toString() { + if len = 2 + then result = "[" + head1.toString() + ", " + head2.toString() + "]" + else + result = "[" + head1.toString() + ", " + head2.toString() + ", ... (" + len.toString() + ")]" + } +} + +private class AccessPathCons1 extends AccessPath, TAccessPathCons1 { + private TypedContent head; + private int len; + + AccessPathCons1() { this = TAccessPathCons1(head, len) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { + Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { result = TCons1(head, len) } + + override int length() { result = len } + + override string toString() { + if len = 1 + then result = "[" + head.toString() + "]" + else result = "[" + head.toString() + ", ... (" + len.toString() + ")]" + } +} + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result } + + /** Gets the `FlowState` of this node. */ + FlowState getState() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getANonHiddenSuccessor() and + reach(this) and + reach(result) + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNodeImpl getASuccessorImpl(); + + private PathNodeImpl getASuccessorIfHidden() { + this.isHidden() and + result = this.getASuccessorImpl() + } + + final PathNodeImpl getANonHiddenSuccessor() { + result = this.getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + abstract NodeEx getNodeEx(); + + predicate isHidden() { + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) + } + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } + + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate directReach(PathNodeImpl n) { + n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor()) +} + +/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ +private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } + +/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNodeImpl n1, PathNode n2) { + n1.getANonHiddenSuccessor() = n2 and directReach(n2) +} + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { + Subpaths::subpaths(arg, par, ret, out) and + reach(arg) and + reach(par) and + reach(ret) and + reach(out) + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + NodeEx node; + FlowState state; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, ap, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbindConf(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = this.getSuccMid() + or + // a final step to a sink + result = this.getSuccMid().projectToSink() + } + + override predicate isSource() { + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + } + + predicate isAtSink() { + sinkNode(node, state, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getState() = state and + result.getConfiguration() = unbindConf(config) + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + NodeEx node; + FlowState state; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, state, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + override Configuration getConfiguration() { result = config } + + override PathNodeImpl getASuccessorImpl() { none() } + + override predicate isSource() { sourceNode(node, state, config) } +} + +private predicate pathNode( + PathNodeMid mid, NodeEx midnode, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, + Configuration conf, LocalCallContext localCC +) { + midnode = mid.getNodeEx() and + state = mid.getState() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + midnode.getEnclosingCallable()) and + ap = mid.getAp() +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +pragma[nomagic] +private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap +) { + exists(NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC | + pathNode(mid, midnode, state0, cc, sc, ap, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, true, _, conf, localCC) + ) + or + exists( + AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC + | + pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + exists(TypedContent tc | pathStoreStep(mid, node, state, ap.pop(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + exists(TypedContent tc | pathReadStep(mid, node, state, ap.push(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, state, _, cc, sc, _, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, state, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, state, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate pathReadStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + tc = ap0.getHead() and + Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, FlowState state, CallContext innercc, AccessPathApprox apa, + Configuration config +) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPathApprox apa, Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, state, innercc, apa, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private NodeEx getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config +) { + result.asNode() = kind.getAnOutNode(call) and + Stage4::revFlow(result, _, apa, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, FlowState state, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, state, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, ParameterPosition ppos, FlowState state, CallContext cc, DataFlowCall call, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(ArgNodeEx arg, ArgumentPosition apos | + pathNode(mid, arg, state, cc, _, ap, config, _) and + arg.asNode().(ArgNode).argumentOf(call, apos) and + apa = ap.getApprox() and + parameterMatch(ppos, apos) + ) +} + +pragma[nomagic] +private predicate parameterCand( + DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config +) { + exists(ParamNodeEx p | + Stage4::revFlow(p, _, apa, config) and + p.isParameterOf(callable, pos) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, AccessPath ap, Configuration config +) { + exists(AccessPathApprox apa | + pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, ap, + pragma[only_bind_into](apa), pragma[only_bind_into](config)) and + callable = resolveCall(call, outercc) and + parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) + ) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +pragma[nomagic] +private predicate pathIntoCallable( + PathNodeMid mid, ParamNodeEx p, FlowState state, CallContext outercc, CallContextCall innercc, + SummaryCtx sc, DataFlowCall call, Configuration config +) { + exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + ( + sc = TSummaryCtxSome(p, state, ap) + or + not exists(TSummaryCtxSome(p, state, ap)) and + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, + AccessPathApprox apa, Configuration config +) { + exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | + pathNode(mid, ret, state, cc, sc, ap, config, _) and + kind = ret.getKind() and + apa = ap.getApprox() and + pos = sc.getParameterPos() and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, state, innercc, sc, ap, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable( + PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, AccessPath ap +) { + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, state, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +private module Subpaths { + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths01( + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + exists(Configuration config | + pathThroughCallable(arg, out, pragma[only_bind_into](sout), _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, _, innercc, sc, _, config) and + paramFlowsThrough(kind, pragma[only_bind_into](sout), innercc, sc, + pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `sout`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths02( + PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and + out.asNode() = kind.getAnOutNode(_) + } + + pragma[nomagic] + private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple. + */ + pragma[nomagic] + private predicate subpaths03( + PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout + ) { + exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | + subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and + pathNode(ret, retnode, sout, innercc, sc, apout, unbindConf(getPathNodeConf(arg)), _) and + kind = retnode.getKind() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, _, n2, _, _, _, _, _) or + store(n1, _, n2, _, _) or + readSet(n1, _, n2, _) + ) + } + + pragma[nomagic] + private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getANonHiddenSuccessor() and + succNode = succ.getNodeEx() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { + exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | + pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and + subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and + not ret.isHidden() and + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() + ) + } + + /** + * Holds if `n` can reach a return node in a summarized subpath that can reach a sink. + */ + predicate retReach(PathNodeImpl n) { + exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) + or + exists(PathNodeImpl mid | + retReach(mid) and + n.getANonHiddenSuccessor() = mid and + not subpaths(_, mid, _, _) + ) + } +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.(PathNodeImpl).getNodeEx().asNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNodeEx().asNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private predicate finalStats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples +) { + fwd = true 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and + tuples = count(PathNode pn) + or + fwd = false 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and + tuples = count(PathNode pn | reach(pn)) +} + +/** + * INTERNAL: Only for debugging. + * + * Calculates per-stage metrics for data flow. + */ +predicate stageStats( + int n, string stage, int nodes, int fields, int conscand, int states, int tuples, + Configuration config +) { + stage = "1 Fwd" and + n = 10 and + Stage1::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "1 Rev" and + n = 15 and + Stage1::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Fwd" and + n = 20 and + Stage2::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Rev" and + n = 25 and + Stage2::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Fwd" and + n = 30 and + Stage3::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Rev" and + n = 35 and + Stage3::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Fwd" and + n = 40 and + Stage4::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Rev" and + n = 45 and + Stage4::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) + or + stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + additionalJumpStateStep(node1, _, node2, _, config) + or + // flow into callable + viableParamArgEx(_, node2, node1) + or + // flow out of a callable + viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) or config.isSource(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private predicate interestingCallableSink(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSink(n) or config.isSink(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSink(mid, config) and callableStep(c, mid, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { + interestingCallableSrc(c, config) or + interestingCallableSink(c, config) + } or + TCallableSrc() or + TCallableSink() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtSink(TCallableSink sink) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, pragma[only_bind_into](config)) and + ce2 = TCallable(c2, pragma[only_bind_into](config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + (config.isSource(n) or config.isSource(n, _)) and + ce2 = TCallable(getNodeEnclosingCallable(n), config) + ) + or + exists(Node n, Configuration config | + ce2 = TCallableSink() and + (config.isSink(n) or config.isSink(n, _)) and + ce1 = TCallable(getNodeEnclosingCallable(n), config) + ) + } + + private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) { + callableExtStepFwd(ce2, ce1) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSinkExt(TCallableExt c) = + shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private int distSink(DataFlowCallable c, Configuration config) { + result = distSinkExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + TypedContent getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private newtype TRevPartialAccessPath = + TRevPartialNil() or + TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `Content`s, but only the first + * element of the list and its length are tracked. + */ + private class RevPartialAccessPath extends TRevPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TRevPartialCons(result, _) } + + int len() { + this = TRevPartialNil() and result = 0 + or + this = TRevPartialCons(_, result) + } + } + + private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil { + override string toString() { result = "" } + } + + private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons { + override string toString() { + exists(Content c, int len | this = TRevPartialCons(c, len) | + if len = 1 + then result = "[" + c.toString() + "]" + else result = "[" + c.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private predicate relevantState(FlowState state) { + sourceNode(_, state, _) or + sinkNode(_, state, _) or + additionalLocalStateStep(_, state, _, _, _) or + additionalLocalStateStep(_, _, _, state, _) or + additionalJumpStateStep(_, state, _, _, _) or + additionalJumpStateStep(_, _, _, state, _) + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParamNodeEx p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TSummaryCtx3 = + TSummaryCtx3None() or + TSummaryCtx3Some(PartialAccessPath ap) + + private newtype TRevSummaryCtx1 = + TRevSummaryCtx1None() or + TRevSummaryCtx1Some(ReturnPosition pos) + + private newtype TRevSummaryCtx2 = + TRevSummaryCtx2None() or + TRevSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TRevSummaryCtx3 = + TRevSummaryCtx3None() or + TRevSummaryCtx3Some(RevPartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeFwd( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = TPartialNil(node.getDataFlowType()) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } or + TPartialPathNodeRev( + NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, TRevSummaryCtx3 sc3, + RevPartialAccessPath ap, Configuration config + ) { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() and + exists(config.explorationLimit()) + or + exists(PartialPathNodeRev mid | + revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and + not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() + ) + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and + if node.asNode() instanceof CastingNode + then compatibleTypes(node.getDataFlowType(), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + 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.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.getNodeEx().projectToNode() = result } + + FlowState getState() { none() } + + private NodeEx getNodeEx() { + result = this.(PartialPathNodeFwd).getNodeEx() or + result = this.(PartialPathNodeRev).getNodeEx() + } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + /** + * Gets the approximate distance to the nearest sink measured in number + * of interprocedural steps. + */ + int getSinkDistance() { + result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | + s = this.(PartialPathNodeFwd).getAp().toString() or + s = this.(PartialPathNodeRev).getAp().toString() + | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">" + } + + /** Holds if this is a source in a forward-flow path. */ + predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() } + + /** Holds if this is a sink in a reverse-flow path. */ + predicate isRevSink() { this.(PartialPathNodeRev).isSink() } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd { + NodeEx node; + FlowState state; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + TSummaryCtx3 sc3; + PartialAccessPath ap; + Configuration config; + + PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, state, cc, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TSummaryCtx3 getSummaryCtx3() { result = sc3 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeFwd getASuccessor() { + partialPathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx1(), result.getSummaryCtx2(), result.getSummaryCtx3(), result.getAp(), + result.getConfiguration()) + } + + predicate isSource() { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap instanceof TPartialNil + } + } + + private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev { + NodeEx node; + FlowState state; + TRevSummaryCtx1 sc1; + TRevSummaryCtx2 sc2; + TRevSummaryCtx3 sc3; + RevPartialAccessPath ap; + Configuration config; + + PartialPathNodeRev() { this = TPartialPathNodeRev(node, state, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + TRevSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TRevSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TRevSummaryCtx3 getSummaryCtx3() { result = sc3 } + + RevPartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeRev getASuccessor() { + revPartialPathStep(result, this.getNodeEx(), this.getState(), this.getSummaryCtx1(), + this.getSummaryCtx2(), this.getSummaryCtx3(), this.getAp(), this.getConfiguration()) + } + + predicate isSink() { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() + } + } + + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalLocalStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsFwd(ap, tc, ap0, config) + ) + or + partialPathIntoCallable(mid, node, state, _, cc, sc1, sc2, sc3, _, ap, config) + or + partialPathOutOfCallable(mid, node, state, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() + or + partialPathThroughCallable(mid, node, state, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + bindingset[result, i] + private int unbindInt(int i) { pragma[only_bind_out](i) = pragma[only_bind_out](result) } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node, + PartialAccessPath ap2 + ) { + exists(NodeEx midNode, DataFlowType contentType | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType, mid.getConfiguration()) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStoreStep(mid, ap1, tc, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc, + Configuration config + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and + ap.getHead() = tc and + pragma[only_bind_into](config) = mid.getConfiguration() and + cc = mid.getCallContext() + ) + } + + private predicate partialPathOutOfCallable0( + PartialPathNodeFwd mid, ReturnPosition pos, FlowState state, CallContext innercc, + PartialAccessPath ap, Configuration config + ) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, state, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, state, cc, ap, config) + | + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodeFwd mid, ParameterPosition ppos, FlowState state, CallContext cc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ArgNode arg, ArgumentPosition apos | + arg = mid.getNodeEx().asNode() and + state = mid.getState() and + cc = mid.getCallContext() and + arg.argumentOf(call, apos) and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, pos, state, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodeFwd mid, ParamNodeEx p, FlowState state, CallContext outercc, + CallContextCall innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ParameterPosition pos, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(state) and + sc3 = TSummaryCtx3Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, FlowState state, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid, RetNodeEx ret | + mid.getNodeEx() = ret and + kind = ret.getKind() and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3 | + partialPathIntoCallable(mid, _, _, cc, innercc, sc1, sc2, sc3, call, _, config) and + paramFlowsThroughInPartialPath(kind, state, innercc, sc1, sc2, sc3, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, state, cc, ap, config) and + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[nomagic] + private predicate revPartialPathStep( + PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, + TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config + ) { + localFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalLocalStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + jumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalJumpStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + revPartialPathReadStep(mid, _, _, node, ap) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(RevPartialAccessPath ap0, Content c | + revPartialPathStoreStep(mid, ap0, c, node, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsRev(ap, c, ap0, config) + ) + or + exists(ParamNodeEx p | + mid.getNodeEx() = p and + viableParamArgEx(_, p, node) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + or + exists(ReturnPosition pos | + revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap, config) and + pos = getReturnPosition(node.asNode()) + ) + or + revPartialPathThroughCallable(mid, node, state, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + pragma[inline] + private predicate revPartialPathReadStep( + PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node, + RevPartialAccessPath ap2 + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + read(node, c, midNode, mid.getConfiguration()) and + ap2.getHead() = c and + ap2.len() = unbindInt(ap1.len() + 1) + ) + } + + pragma[nomagic] + private predicate apConsRev( + RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeRev mid | + revPartialPathReadStep(mid, ap1, c, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathStoreStep( + PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config + ) { + exists(NodeEx midNode, TypedContent tc | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + store(node, tc, midNode, _, config) and + ap.getHead() = c and + config = mid.getConfiguration() and + tc.getContent() = c + ) + } + + pragma[nomagic] + private predicate revPartialPathIntoReturn( + PartialPathNodeRev mid, ReturnPosition pos, FlowState state, TRevSummaryCtx1Some sc1, + TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3, DataFlowCall call, RevPartialAccessPath ap, + Configuration config + ) { + exists(NodeEx out | + mid.getNodeEx() = out and + mid.getState() = state and + viableReturnPosOutEx(call, pos, out) and + sc1 = TRevSummaryCtx1Some(pos) and + sc2 = TRevSummaryCtx2Some(state) and + sc3 = TRevSummaryCtx3Some(ap) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathFlowsThrough( + ArgumentPosition apos, FlowState state, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, + TRevSummaryCtx3Some sc3, RevPartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos | + mid.getNodeEx() = p and + mid.getState() = state and + p.getPosition() = ppos and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable0( + DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, FlowState state, + RevPartialAccessPath ap, Configuration config + ) { + exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3 | + revPartialPathIntoReturn(mid, _, _, sc1, sc2, sc3, call, _, config) and + revPartialPathFlowsThrough(pos, state, sc1, sc2, sc3, ap, config) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable( + PartialPathNodeRev mid, ArgNodeEx node, FlowState state, RevPartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ArgumentPosition pos | + revPartialPathThroughCallable0(call, mid, pos, state, ap, config) and + node.asNode().(ArgNode).argumentOf(call, pos) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + source.isFwdSource() and + node = source.getASuccessor+() +} + +private predicate revPartialFlow( + PartialPathNode node, PartialPathNode sink, Configuration configuration +) { + sink.getConfiguration() = configuration and + sink.isRevSink() and + node.getASuccessor+() = sink +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll new file mode 100644 index 00000000000..468f8640a78 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -0,0 +1,4450 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. This file exists in several identical + * copies, allowing queries to use multiple `Configuration` classes that depend + * on each other without introducing mutual recursion among those configurations. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ```ql + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(Node source) { none() } + + /** + * Holds if `source` is a relevant data flow source with the given initial + * `state`. + */ + predicate isSource(Node source, FlowState state) { none() } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(Node sink) { none() } + + /** + * Holds if `sink` is a relevant data flow sink accepting `state`. + */ + predicate isSink(Node source, FlowState state) { none() } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** + * Holds if data flow through `node` is prohibited when the flow state is + * `state`. + */ + predicate isBarrier(Node node, FlowState state) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited when + * the flow state is `state` + */ + deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) { + none() + } + + /** + * Holds if an arbitrary number of implicit read steps of content `c` may be + * taken at `node`. + */ + predicate allowImplicitRead(Node node, ContentSet c) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` + * measured in approximate number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } + + /** + * Holds if there is a partial data flow path from `node` to `sink`. The + * approximate distance between `node` and the closest sink is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards source definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sinks is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + * + * Note that reverse flow has slightly lower precision than the corresponding + * forward flow, as reverse flow disregards type pruning among other features. + */ + final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) { + revPartialFlow(node, sink, this) and + dist = node.getSinkDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSource(n, _)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n | this.isSink(n, _)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0 + or + super.hasFlow(source, sink) + } +} + +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 class ArgNodeEx extends NodeEx { + ArgNodeEx() { this.asNode() instanceof ArgNode } +} + +private class ParamNodeEx extends NodeEx { + ParamNodeEx() { this.asNode() instanceof ParamNode } + + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + this.asNode().(ParamNode).isParameterOf(c, pos) + } + + ParameterPosition getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } +} + +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) + | + config.isSource(n) or config.isSource(n, _) + ) +} + +private predicate outBarrier(NodeEx node, Configuration config) { + exists(Node n | + node.asNode() = n and + config.isBarrierOut(n) + | + config.isSink(n) or config.isSink(n, _) + ) +} + +/** A bridge class to access the deprecated `isBarrierGuard`. */ +private class BarrierGuardGuardedNodeBridge extends Unit { + abstract predicate guardedNode(Node n, Configuration config); + + abstract predicate guardedNode(Node n, FlowState state, Configuration config); +} + +private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge { + deprecated override predicate guardedNode(Node n, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g) and + n = g.getAGuardedNode() + ) + } + + deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g, state) and + n = g.getAGuardedNode() + ) + } +} + +pragma[nomagic] +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) and + not config.isSource(n, _) + or + config.isBarrierOut(n) and + not config.isSink(n) and + not config.isSink(n, _) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config) + ) +} + +pragma[nomagic] +private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) { + exists(Node n | node.asNode() = n | + config.isBarrier(n, state) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config) + ) +} + +pragma[nomagic] +private predicate sourceNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSource(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSource(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +pragma[nomagic] +private predicate sinkNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSink(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSink(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +/** Provides the relevant barriers for a step from `node1` to `node2`. */ +pragma[inline] +private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) { + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.asNode() = n and + node2.isImplicitReadNode(n, false) and + not fullBarrier(node1, config) + ) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.isImplicitReadNode(n, true) and + node2.asNode() = n and + not fullBarrier(node2, config) + ) +} + +private predicate additionalLocalStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) + ) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate additionalJumpStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +pragma[nomagic] +private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and + stepFilter(node1, node2, config) + or + exists(Node n | + node2.isImplicitReadNode(n, true) and + node1.isImplicitReadNode(n, _) and + config.allowImplicitRead(n, c) + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { + exists(ContentSet cs | + readSet(node1, cs, node2, config) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate clearsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + clearsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + +pragma[nomagic] +private predicate store( + NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config +) { + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and + read(_, tc.getContent(), _, config) and + stepFilter(node1, node2, 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()) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private module Stage1 implements StageSig { + class ApApprox = Unit; + + class Ap = Unit; + + class ApOption = Unit; + + class Cc = boolean; + + /* Begin: Stage 1 logic. */ + /** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `cc` records whether the node is reached through an + * argument in a call. + */ + predicate fwdFlow(NodeEx node, Cc cc, Configuration config) { + sourceNode(node, _, config) and + if hasSourceCallCtx(config) then cc = true else cc = false + or + exists(NodeEx mid | fwdFlow(mid, cc, config) | + localFlowStep(mid, node, config) or + additionalLocalFlowStep(mid, node, config) or + additionalLocalStateStep(mid, _, node, _, config) + ) + or + exists(NodeEx mid | fwdFlow(mid, _, config) and cc = false | + jumpStep(mid, node, config) or + additionalJumpStep(mid, node, config) or + additionalJumpStateStep(mid, _, node, _, config) + ) + or + // store + exists(NodeEx mid | + useFieldFlow(config) and + fwdFlow(mid, cc, config) and + store(mid, _, node, _, config) + ) + or + // read + exists(ContentSet c | + fwdFlowReadSet(c, node, cc, config) and + fwdFlowConsCandSet(c, _, config) + ) + or + // flow into a callable + exists(NodeEx arg | + fwdFlow(arg, _, config) and + viableParamArgEx(_, node, arg) and + cc = true and + not fullBarrier(node, config) + ) + or + // flow out of a callable + exists(DataFlowCall call | + fwdFlowOut(call, node, false, config) and + cc = false + or + fwdFlowOutFromArg(call, node, config) and + fwdFlowIsEntered(call, cc, config) + ) + } + + private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) } + + pragma[nomagic] + private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) { + exists(NodeEx mid | + fwdFlow(mid, cc, config) and + readSet(mid, c, node, config) + ) + } + + /** + * Holds if `c` is the target of a store in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, TypedContent tc | + not fullBarrier(node, config) and + useFieldFlow(config) and + fwdFlow(mid, _, config) and + store(mid, tc, node, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `cs` may be interpreted in a read as the target of some store + * into `c`, in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) { + fwdFlowConsCand(c, config) and + c = cs.getAReadContent() + } + + pragma[nomagic] + private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) { + exists(RetNodeEx ret | + fwdFlow(ret, cc, config) and + ret.getReturnPosition() = pos + ) + } + + pragma[nomagic] + private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) { + exists(ReturnPosition pos | + fwdFlowReturnPosition(pos, cc, config) and + viableReturnPosOutEx(call, pos, out) and + not fullBarrier(out, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) { + fwdFlowOut(call, out, true, config) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { + exists(ArgNodeEx arg | + fwdFlow(arg, cc, config) and + viableParamArgEx(call, _, arg) + ) + } + + private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1 | + additionalLocalStateStep(node1, state1, _, state2, config) or + additionalJumpStateStep(node1, state1, _, state2, config) + | + fwdFlow(node1, config) + ) + } + + private predicate fwdFlowState(FlowState state, Configuration config) { + sourceNode(_, state, config) + or + exists(FlowState state0 | + fwdFlowState(state0, config) and + stateStepFwd(state0, state, config) + ) + } + + /** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ + pragma[nomagic] + predicate revFlow(NodeEx node, boolean toReturn, Configuration config) { + revFlow0(node, toReturn, config) and + fwdFlow(node, config) + } + + pragma[nomagic] + private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { + exists(FlowState state | + fwdFlow(node, pragma[only_bind_into](config)) and + sinkNode(node, state, config) and + fwdFlowState(state, pragma[only_bind_into](config)) and + if hasSinkCallCtx(config) then toReturn = true else toReturn = false + ) + or + exists(NodeEx mid | revFlow(mid, toReturn, config) | + localFlowStep(node, mid, config) or + additionalLocalFlowStep(node, mid, config) or + additionalLocalStateStep(node, _, mid, _, config) + ) + or + exists(NodeEx mid | revFlow(mid, _, config) and toReturn = false | + jumpStep(node, mid, config) or + additionalJumpStep(node, mid, config) or + additionalJumpStateStep(node, _, mid, _, config) + ) + or + // store + exists(Content c | + revFlowStore(c, node, toReturn, config) and + revFlowConsCand(c, config) + ) + or + // read + exists(NodeEx mid, ContentSet c | + readSet(node, c, mid, config) and + fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and + revFlow(mid, toReturn, pragma[only_bind_into](config)) + ) + or + // flow into a callable + exists(DataFlowCall call | + revFlowIn(call, node, false, config) and + toReturn = false + or + revFlowInToReturn(call, node, config) and + revFlowIsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + revFlowOut(pos, config) and + node.(RetNodeEx).getReturnPosition() = pos and + toReturn = true + ) + } + + /** + * Holds if `c` is the target of a read in the flow covered by `revFlow`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, ContentSet cs | + fwdFlow(node, pragma[only_bind_into](config)) and + readSet(node, cs, mid, config) and + fwdFlowConsCandSet(cs, 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, 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, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `c` is the target of both a read and a store in the flow covered + * by `revFlow`. + */ + pragma[nomagic] + predicate revFlowIsReadAndStored(Content c, Configuration conf) { + revFlowConsCand(c, conf) and + revFlowStore(c, _, _, conf) + } + + pragma[nomagic] + predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config + ) { + fwdFlowReturnPosition(pos, _, config) and + viableReturnPosOutEx(call, pos, out) + } + + pragma[nomagic] + private predicate revFlowOut(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, NodeEx out | + revFlow(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) + } + + pragma[nomagic] + predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config + ) { + viableParamArgEx(call, p, arg) and + fwdFlow(arg, config) + } + + pragma[nomagic] + 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, ArgNodeEx arg, Configuration config) { + revFlowIn(call, arg, true, config) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(NodeEx out | + revFlow(out, toReturn, config) and + fwdFlowOutFromArg(call, out, config) + ) + } + + private predicate stateStepRev(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + additionalLocalStateStep(node1, state1, node2, state2, config) or + additionalJumpStateStep(node1, state1, node2, state2, config) + | + revFlow(node1, _, pragma[only_bind_into](config)) and + revFlow(node2, _, pragma[only_bind_into](config)) and + fwdFlowState(state1, pragma[only_bind_into](config)) and + fwdFlowState(state2, pragma[only_bind_into](config)) + ) + } + + predicate revFlowState(FlowState state, Configuration config) { + exists(NodeEx node | + sinkNode(node, state, config) and + revFlow(node, _, pragma[only_bind_into](config)) and + fwdFlowState(state, pragma[only_bind_into](config)) + ) + or + exists(FlowState state0 | + revFlowState(state0, config) and + stateStepRev(state, state0, config) + ) + } + + pragma[nomagic] + predicate storeStepCand( + 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, config) and + c = tc.getContent() and + exists(ap1) + ) + } + + pragma[nomagic] + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + read(n1, c, n2, pragma[only_bind_into](config)) and + revFlow(n2, pragma[only_bind_into](config)) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, _, pragma[only_bind_into](config)) and + exists(state) and + exists(ap) + } + + private predicate throughFlowNodeCand(NodeEx node, Configuration config) { + revFlow(node, true, config) and + fwdFlow(node, true, config) and + not inBarrier(node, config) and + not outBarrier(node, config) + } + + /** Holds if flow may return from `callable`. */ + pragma[nomagic] + private predicate returnFlowCallableNodeCand( + DataFlowCallable callable, ReturnKindExt kind, Configuration config + ) { + exists(RetNodeEx ret | + throughFlowNodeCand(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) + } + + /** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ + pragma[nomagic] + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand(p, config) and + returnFlowCallableNodeCand(c, kind, config) and + p.getEnclosingCallable() = c and + exists(ap) and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists(ArgNodeEx arg, boolean toReturn | + revFlow(arg, toReturn, config) and + revFlowInToReturn(call, arg, config) and + revFlowIsReturned(call, toReturn, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true and + nodes = count(NodeEx node | fwdFlow(node, config)) and + fields = count(Content f0 | fwdFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | fwdFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config)) + or + fwd = false and + nodes = count(NodeEx node | revFlow(node, _, config)) and + fields = count(Content f0 | revFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | revFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | revFlow(n, b, config)) + } + /* End: Stage 1 logic. */ +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) { + Stage1::revFlow(node2, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +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, NodeEx out, Configuration config +) { + Stage1::revFlow(out, config) and + Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config +) { + viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and + Stage1::revFlow(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config +) { + Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and + Stage1::revFlow(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + Stage1::revFlow(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(NodeEx n1, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(NodeEx n2, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +private signature module StageSig { + class Ap; + + predicate revFlow(NodeEx node, Configuration config); + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); + + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); + + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ); + + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config); +} + +private module MkStage { + class ApApprox = PrevStage::Ap; + + signature module StageParam { + class Ap; + + class ApNil extends Ap; + + bindingset[result, ap] + ApApprox getApprox(Ap ap); + + ApNil getApNil(NodeEx node); + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail); + + Content getHeadContent(Ap ap); + + class ApOption; + + ApOption apNone(); + + ApOption apSome(Ap ap); + + class Cc; + + class CcCall extends Cc; + + // TODO: member predicate on CcCall + predicate matchesCall(CcCall cc, DataFlowCall call); + + class CcNoCall extends Cc; + + Cc ccNone(); + + CcCall ccSomeCall(); + + class LocalCc; + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc); + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc); + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc); + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ); + + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config + ); + + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config + ); + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config); + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType); + } + + module Stage implements StageSig { + import Param + + /* Begin: Stage logic. */ + bindingset[result, apa] + private ApApprox unbindApa(ApApprox apa) { + pragma[only_bind_out](apa) = pragma[only_bind_out](result) + } + + pragma[nomagic] + private predicate flowThroughOutOfCall( + DataFlowCall call, CcCall ccc, 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(_, ret.getEnclosingCallable(), _, + pragma[only_bind_into](config)) and + matchesCall(ccc, call) + } + + /** + * Holds if `node` is reachable with access path `ap` from a source in the + * configuration `config`. + * + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ + pragma[nomagic] + predicate fwdFlow( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + fwdFlow0(node, state, cc, argAp, ap, config) and + PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and + filter(node, state, ap, config) + } + + pragma[nomagic] + private predicate fwdFlow0( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + sourceNode(node, state, config) and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and + argAp = apNone() and + ap = getApNil(node) + or + exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | + fwdFlow(mid, state0, cc, argAp, ap0, config) and + localCc = getLocalCc(mid, cc) + | + localStep(mid, state0, node, state, true, _, config, localCc) and + ap = ap0 + or + localStep(mid, state0, node, state, false, ap, config, localCc) and + ap0 instanceof ApNil + ) + or + exists(NodeEx mid | + fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + jumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() + ) + or + exists(NodeEx mid, ApNil nil | + fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStateStep(mid, state0, node, state, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + // store + exists(TypedContent tc, Ap ap0 | + fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and + ap = apCons(tc, ap0) + ) + or + // read + exists(Ap ap0, Content c | + fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and + fwdFlowConsCand(ap0, c, ap, config) + ) + or + // flow into a callable + exists(ApApprox apa | + fwdFlowIn(_, node, state, _, cc, _, ap, config) and + apa = getApprox(ap) and + if PrevStage::parameterMayFlowThrough(node, _, apa, config) + then argAp = apSome(ap) + else argAp = apNone() + ) + or + // flow out of a callable + fwdFlowOutNotFromArg(node, state, cc, argAp, ap, config) + or + exists(DataFlowCall call, Ap argAp0 | + fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and + fwdFlowIsEntered(call, cc, argAp, argAp0, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowStore( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + exists(DataFlowType contentType | + fwdFlow(node1, state, cc, argAp, ap1, config) and + PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and + typecheckStore(ap1, contentType) + ) + } + + /** + * Holds if forward flow with access path `tail` reaches a store of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(TypedContent tc | + fwdFlowStore(_, tail, tc, _, _, _, _, config) and + tc.getContent() = c and + cons = apCons(tc, tail) + ) + } + + pragma[nomagic] + private predicate fwdFlowRead( + Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + fwdFlow(node1, state, cc, argAp, ap, config) and + PrevStage::readStepCand(node1, c, node2, config) and + getHeadContent(ap) = c + } + + pragma[nomagic] + private predicate fwdFlowIn( + DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, + Ap ap, Configuration config + ) { + exists(ArgNodeEx arg, boolean allowsFieldFlow | + fwdFlow(arg, state, outercc, argAp, ap, config) and + flowIntoCall(call, arg, p, allowsFieldFlow, config) and + innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutNotFromArg( + NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config + ) { + exists( + DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, + DataFlowCallable inner + | + fwdFlow(ret, state, innercc, argAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + inner = ret.getEnclosingCallable() and + ccOut = getCallContextReturn(inner, call, innercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg( + DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc | + fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and + flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow` + * and data might flow through the target callable and back out at `call`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered( + DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p | + fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and + PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) + ) + } + + pragma[nomagic] + private predicate storeStepFwd( + 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( + 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, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, + pragma[only_bind_into](config)) and + fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate flowThroughIntoCall( + 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 + PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and + callMayFlowThroughFwd(call, pragma[only_bind_into](config)) + } + + pragma[nomagic] + private predicate returnNodeMayFlowThrough( + RetNodeEx ret, FlowState state, Ap ap, Configuration config + ) { + fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config) + } + + /** + * Holds if `node` with access path `ap` is part of a path from a source to a + * sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from the + * enclosing callable in order to reach a sink, and if so, `returnAp` records + * the access path of the returned value. + */ + pragma[nomagic] + predicate revFlow( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + revFlow0(node, state, toReturn, returnAp, ap, config) and + fwdFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + private predicate revFlow0( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + fwdFlow(node, state, _, _, ap, config) and + sinkNode(node, state, config) and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and + returnAp = apNone() and + ap instanceof ApNil + or + exists(NodeEx mid, FlowState state0 | + localStep(node, state, mid, state0, true, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, ap, config) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and + ap instanceof ApNil + ) + or + exists(NodeEx mid | + jumpStep(node, mid, config) and + revFlow(mid, state, _, _, ap, config) and + toReturn = false and + returnAp = apNone() + ) + or + 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), state, _, _, nil, pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and + additionalJumpStateStep(node, state, mid, state0, config) and + revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, + pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + // store + exists(Ap ap0, Content c | + revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and + revFlowConsCand(ap0, c, ap, config) + ) + or + // read + exists(NodeEx mid, Ap ap0 | + revFlow(mid, state, toReturn, returnAp, ap0, config) and + readStepFwd(node, ap, _, mid, ap0, config) + ) + or + // flow into a callable + revFlowInNotToReturn(node, state, returnAp, ap, config) and + toReturn = false + or + exists(DataFlowCall call, Ap returnAp0 | + revFlowInToReturn(call, node, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + or + // flow out of a callable + revFlowOut(_, node, state, _, _, ap, config) and + toReturn = true and + if returnNodeMayFlowThrough(node, state, ap, config) + then returnAp = apSome(ap) + else returnAp = apNone() + } + + pragma[nomagic] + private predicate revFlowStore( + Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, + boolean toReturn, ApOption returnAp, Configuration config + ) { + revFlow(mid, state, toReturn, returnAp, ap0, config) and + storeStepFwd(node, ap, tc, mid, ap0, config) and + tc.getContent() = c + } + + /** + * Holds if reverse flow with access path `tail` reaches a read of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(NodeEx mid, Ap tail0 | + revFlow(mid, _, _, _, tail, config) and + tail = pragma[only_bind_into](tail0) and + readStepFwd(_, cons, c, mid, tail0, config) + ) + } + + pragma[nomagic] + private predicate revFlowOut( + DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, + Configuration config + ) { + exists(NodeEx out, boolean allowsFieldFlow | + revFlow(out, state, toReturn, returnAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInNotToReturn( + ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, false, returnAp, ap, config) and + flowIntoCall(_, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInToReturn( + DataFlowCall call, ArgNodeEx arg, FlowState state, Ap returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, true, apSome(returnAp), ap, config) and + flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned( + DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, FlowState state, CcCall ccc | + revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and + fwdFlow(ret, state, ccc, apSome(_), ap, config) and + matchesCall(ccc, call) + ) + } + + pragma[nomagic] + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ) { + exists(Ap ap2, Content c | + PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and + revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and + revFlowConsCand(ap2, c, ap1, 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 + revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _, _, + pragma[only_bind_into](config)) + ) + } + + predicate revFlow(NodeEx node, FlowState state, Configuration config) { + revFlow(node, state, _, _, _, config) + } + + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, ap, config) + } + + private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepFwd(_, ap, tc, _, _, config) + } + + private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepCand(_, ap, tc, _, _, config) + } + + private predicate validAp(Ap ap, Configuration config) { + revFlow(_, _, _, _, ap, config) and ap instanceof ApNil + or + exists(TypedContent head, Ap tail | + consCand(head, tail, config) and + ap = apCons(head, tail) + ) + } + + predicate consCand(TypedContent tc, Ap ap, Configuration config) { + revConsCand(tc, ap, config) and + validAp(ap, config) + } + + pragma[noinline] + private predicate parameterFlow( + ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config + ) { + revFlow(p, _, true, apSome(ap0), ap, config) and + c = p.getEnclosingCallable() + } + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | + parameterFlow(p, ap, ap0, c, config) and + c = ret.getEnclosingCallable() and + revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), + pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and + fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and + kind = ret.getKind() and + p.getPosition() = pos and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists( + Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap + | + revFlow(arg, state, toReturn, returnAp, ap, config) and + revFlowInToReturn(call, arg, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true 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 + states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(n, state, cc, argAp, ap, config) + ) + or + fwd = false 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 + states = count(FlowState state | revFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | + revFlow(n, state, b, retAp, ap, config) + ) + } + /* End: Stage logic. */ + } +} + +private module BooleanCallContext { + class Cc extends boolean { + Cc() { this in [true, false] } + } + + class CcCall extends Cc { + CcCall() { this = true } + } + + /** Holds if the call context may be `call`. */ + predicate matchesCall(CcCall cc, DataFlowCall call) { any() } + + class CcNoCall extends Cc { + CcNoCall() { this = false } + } + + Cc ccNone() { result = false } + + CcCall ccSomeCall() { result = true } + + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } +} + +private module Level1CallContext { + class Cc = CallContext; + + class CcCall = CallContextCall; + + pragma[inline] + predicate matchesCall(CcCall cc, DataFlowCall call) { cc.matchesCall(call) } + + class CcNoCall = CallContextNoCall; + + Cc ccNone() { result instanceof CallContextAny } + + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + + module NoLocalCallContext { + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } + } + + module LocalCallContext { + class LocalCc = LocalCallContext; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { + result = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + node.getEnclosingCallable()) + } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall() + } + } + + bindingset[call, c, innercc] + 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() + } +} + +private module Stage2Param implements MkStage::StageParam { + private module PrevStage = Stage1; + + class Ap extends boolean { + Ap() { this in [true, false] } + } + + class ApNil extends Ap { + ApNil() { this = false } + } + + bindingset[result, ap] + PrevStage::Ap getApprox(Ap ap) { any() } + + ApNil getApNil(NodeEx node) { Stage1::revFlow(node, _) and exists(result) } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) } + + pragma[inline] + Content getHeadContent(Ap ap) { exists(result) and ap = true } + + class ApOption = BooleanOption; + + ApOption apNone() { result = TBooleanNone() } + + ApOption apSome(Ap ap) { result = TBooleanSome(ap) } + + import Level1CallContext + import NoLocalCallContext + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + ( + preservesValue = true and + localFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalStateStep(node1, state1, node2, state2, config) + ) and + exists(ap) and + exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand1/5; + + predicate flowIntoCall = flowIntoCallNodeCand1/5; + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + PrevStage::revFlowState(state, pragma[only_bind_into](config)) and + exists(ap) and + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage2 implements StageSig { + import MkStage::Stage +} + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +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 NodeEx { + FlowCheckNode() { + castNode(this.asNode()) or + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) + } + } + + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) { + Stage2::revFlow(node, state, config) and + ( + sourceNode(node, state, config) + or + jumpStep(_, node, config) + or + additionalJumpStep(_, node, config) + or + additionalJumpStateStep(_, _, node, state, config) + or + node instanceof ParamNodeEx + or + node.asNode() instanceof OutNodeExt + or + Stage2::storeStepCand(_, _, _, node, _, config) + or + Stage2::readStepCand(_, _, node, config) + or + node instanceof FlowCheckNode + or + exists(FlowState s | + additionalLocalStateStep(_, s, node, state, config) and + s != state + ) + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(NodeEx node, FlowState state, Configuration config) { + exists(NodeEx next | Stage2::revFlow(next, state, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + Stage2::storeStepCand(node, _, _, next, _, config) or + Stage2::readStepCand(node, _, next, config) + ) + or + exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) | + additionalJumpStateStep(node, state, next, s, config) + or + additionalLocalStateStep(node, state, next, s, config) and + s != state + ) + or + Stage2::revFlow(node, state, config) and + node instanceof FlowCheckNode + or + sinkNode(node, state, config) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, Configuration config + ) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 and + Stage2::revFlow(node1, pragma[only_bind_into](state1), false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, pragma[only_bind_into](state2), false, + pragma[only_bind_into](config)) + or + additionalLocalStateStep(node1, state1, node2, state2, config) and + Stage2::revFlow(node1, state1, false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, state2, false, pragma[only_bind_into](config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t, + Configuration config, LocalCallContext cc + ) { + not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = node1.getDataFlowType() and // irrelevant dummy value + Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config)) + or + additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and + preservesValue = false and + t = node2.getDataFlowType() + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) + or + exists(NodeEx mid | + localFlowStepPlus(node1, pragma[only_bind_into](state), 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](state), pragma[only_bind_into](config)) + ) + or + exists(NodeEx mid | + localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and + additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and + not mid instanceof FlowCheckNode and + preservesValue = false and + t = node2.getDataFlowType() + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + AccessPathFrontNil apf, Configuration config, LocalCallContext callContext + ) { + localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, state1, config) and + state1 = state2 + or + additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and + state1 != state2 and + preservesValue = false and + apf = TFrontNil(node2.getDataFlowType()) and + callContext.relevantFor(node1.getEnclosingCallable()) and + not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | + isUnreachableInCallCached(node1.asNode(), call) or + isUnreachableInCallCached(node2.asNode(), call) + ) + } +} + +private import LocalFlowBigStep + +private module Stage3Param implements MkStage::StageParam { + private module PrevStage = Stage2; + + class Ap = AccessPathFront; + + class ApNil = AccessPathFrontNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathFrontOption; + + ApOption apNone() { result = TAccessPathFrontNone() } + + ApOption apSome(Ap ap) { result = TAccessPathFrontSome(ap) } + + import BooleanCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand2/5; + + predicate flowIntoCall = flowIntoCallNodeCand2/5; + + pragma[nomagic] + private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { + PrevStage::revFlow(node, config) and + clearsContentCached(node.asNode(), c) + } + + pragma[nomagic] + private predicate clearContent(NodeEx node, Content c, Configuration config) { + exists(ContentSet cs | + PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and + c = cs.getAReadContent() and + clearSet(node, cs, pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate clear(NodeEx node, Ap ap, Configuration config) { + clearContent(node, ap.getHead().getContent(), config) + } + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + + pragma[nomagic] + private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + exists(state) and + exists(config) and + not clear(node, ap, config) and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { + // We need to typecheck stores here, since reverse flow through a getter + // might have a different type here compared to inside the getter. + compatibleTypes(ap.getType(), contentType) + } +} + +private module Stage3 implements StageSig { + import MkStage::Stage +} + +/** + * Holds if `argApf` is recorded as the summary context for flow reaching `node` + * and remains relevant for the following pruning stage. + */ +private predicate flowCandSummaryCtx( + NodeEx node, FlowState state, AccessPathFront argApf, Configuration config +) { + exists(AccessPathFront apf | + Stage3::revFlow(node, state, true, _, apf, config) and + Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) + ) +} + +/** + * Holds if a length 2 access path approximation with the head `tc` is expected + * to be expensive. + */ +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(NodeEx n, FlowState state | + Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + or + flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + ) and + accessPathApproxCostLimits(apLimit, tupleLimit) and + apLimit < tails and + tupleLimit < (tails - 1) * nodes and + not tc.forceHighPrecision() + ) +} + +private newtype TAccessPathApprox = + TNil(DataFlowType t) or + TConsNil(TypedContent tc, DataFlowType t) { + Stage3::consCand(tc, TFrontNil(t), _) and + not expensiveLen2unfolding(tc, _) + } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + Stage3::consCand(tc1, TFrontHead(tc2), _) and + len in [2 .. accessPathLimit()] and + not expensiveLen2unfolding(tc1, _) + } or + TCons1(TypedContent tc, int len) { + len in [1 .. accessPathLimit()] and + expensiveLen2unfolding(tc, _) + } + +/** + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence of dereference operations needed to get from the value in the node + * to the tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPathApprox extends TAccessPathApprox { + abstract string toString(); + + abstract TypedContent getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); +} + +private class AccessPathApproxNil extends AccessPathApprox, TNil { + private DataFlowType t; + + AccessPathApproxNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override TypedContent getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override AccessPathApprox pop(TypedContent head) { none() } +} + +abstract private class AccessPathApproxCons extends AccessPathApprox { } + +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; + private DataFlowType t; + + AccessPathApproxConsNil() { this = TConsNil(tc, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override TypedContent getHead() { result = tc } + + override int len() { result = 1 } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } +} + +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; + private int len; + + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } + + override string toString() { + if len = 2 + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc1 } + + override int len() { result = len } + + override DataFlowType getType() { result = tc1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc1) } + + override AccessPathApprox pop(TypedContent head) { + head = tc1 and + ( + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + } +} + +private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 { + private TypedContent tc; + private int len; + + AccessPathApproxCons1() { this = TCons1(tc, len) } + + override string toString() { + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc } + + override int len() { result = len } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { + head = tc and + ( + exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + or + exists(DataFlowType t | + len = 1 and + Stage3::consCand(tc, TFrontNil(t), _) and + result = TNil(t) + ) + ) + } +} + +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } + +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } + +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) + +private class AccessPathApproxOption extends TAccessPathApproxOption { + string toString() { + this = TAccessPathApproxNone() and result = "" + or + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) + } +} + +private module Stage4Param implements MkStage::StageParam { + private module PrevStage = Stage3; + + class Ap = AccessPathApprox; + + class ApNil = AccessPathApproxNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathApproxOption; + + ApOption apNone() { result = TAccessPathApproxNone() } + + ApOption apSome(Ap ap) { result = TAccessPathApproxSome(ap) } + + import Level1CallContext + import LocalCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) + } + + pragma[nomagic] + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config + ) { + exists(FlowState state | + flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow, + Configuration config + ) { + exists(FlowState state | + flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { any() } + + // Type checking is not necessary here as it has already been done in stage 3. + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage4 = MkStage::Stage; + +bindingset[conf, result] +private Configuration unbindConf(Configuration conf) { + exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c)) +} + +pragma[nomagic] +private predicate nodeMayUseSummary0( + NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(AccessPathApprox apa0 | + Stage4::parameterMayFlowThrough(_, c, _, _) and + Stage4::revFlow(n, state, true, _, apa0, config) and + Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and + n.getEnclosingCallable() = c + ) +} + +pragma[nomagic] +private predicate nodeMayUseSummary( + NodeEx n, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(DataFlowCallable c | + Stage4::parameterMayFlowThrough(_, c, apa, config) and + nodeMayUseSummary0(n, c, state, apa, config) + ) +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { + exists(Configuration config | + Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and + Stage4::revFlow(p, state, _, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParamNodeEx p; + private FlowState s; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, s, ap) } + + ParameterPosition getParameterPos() { p.isParameterOf(_, result) } + + ParamNodeEx getParamNode() { result = p } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** + * Gets the number of length 2 access path approximations that correspond to `apa`. + */ +private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) { + exists(TypedContent tc, int len | + tc = apa.getHead() and + len = apa.len() and + result = + strictcount(AccessPathFront apf | + Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), + config) + ) + ) +} + +private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { + result = + strictcount(NodeEx n, FlowState state | + Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) + ) +} + +/** + * Holds if a length 2 access path approximation matching `apa` is expected + * to be expensive. + */ +private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configuration config) { + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = count1to2unfold(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + apLimit < aps and + tupleLimit < (aps - 1) * nodes + ) +} + +private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { + exists(TypedContent head | + apa.pop(head) = result and + Stage4::consCand(head, result, config) + ) +} + +/** + * Holds with `unfold = false` if a precise head-tail representation of `apa` is + * expected to be expensive. Holds with `unfold = true` otherwise. + */ +private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) { + if apa.getHead().forceHighPrecision() + then unfold = true + else + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = countPotentialAps(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true + ) +} + +/** + * Gets the number of `AccessPath`s that correspond to `apa`. + */ +private int countAps(AccessPathApprox apa, Configuration config) { + evalUnfold(apa, false, config) and + result = 1 and + (not apa instanceof AccessPathApproxCons1 or expensiveLen1to2unfolding(apa, config)) + or + evalUnfold(apa, false, config) and + result = count1to2unfold(apa, config) and + not expensiveLen1to2unfolding(apa, config) + or + evalUnfold(apa, true, config) and + result = countPotentialAps(apa, config) +} + +/** + * Gets the number of `AccessPath`s that would correspond to `apa` assuming + * that it is expanded to a precise head-tail representation. + */ +language[monotonicAggregates] +private int countPotentialAps(AccessPathApprox apa, Configuration config) { + apa instanceof AccessPathApproxNil and result = 1 + or + result = strictsum(AccessPathApprox tail | tail = getATail(apa, config) | countAps(tail, config)) +} + +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { + exists(AccessPathApproxCons apa | + not evalUnfold(apa, false, _) and + head = apa.getHead() and + tail.getApprox() = getATail(apa, _) + ) + } or + TAccessPathCons2(TypedContent head1, TypedContent head2, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + not expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head1 = apa.getHead() and + head2 = getATail(apa, _).getHead() + ) + } or + TAccessPathCons1(TypedContent head, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head = apa.getHead() + ) + } + +private newtype TPathNode = + TPathNodeMid( + NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config + ) { + // A PathNode is introduced by a source ... + Stage4::revFlow(node, state, config) and + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, state, cc, sc, ap) and + pragma[only_bind_into](config) = mid.getConfiguration() and + Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) + ) + } or + TPathNodeSink(NodeEx node, FlowState state, Configuration config) { + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + state = sink.getState() and + config = sink.getConfiguration() + ) + } + +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * of dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +private class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + or + result = TCons1(head, this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl(boolean needsSuffix) { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + needsSuffix = false and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl(needsSuffix) + or + exists(TypedContent tc2, TypedContent tc3, int len | tail = TAccessPathCons2(tc2, tc3, len) | + result = head + ", " + tc2 + ", " + tc3 + ", ... (" and len > 2 and needsSuffix = true + or + result = head + ", " + tc2 + ", " + tc3 + "]" and len = 2 and needsSuffix = false + ) + or + exists(TypedContent tc2, int len | tail = TAccessPathCons1(tc2, len) | + result = head + ", " + tc2 + ", ... (" and len > 1 and needsSuffix = true + or + result = head + ", " + tc2 + "]" and len = 1 and needsSuffix = false + ) + } + + override string toString() { + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" + or + result = "[" + this.toStringImpl(false) + } +} + +private class AccessPathCons2 extends AccessPath, TAccessPathCons2 { + private TypedContent head1; + private TypedContent head2; + private int len; + + AccessPathCons2() { this = TAccessPathCons2(head1, head2, len) } + + override TypedContent getHead() { result = head1 } + + override AccessPath getTail() { + Stage4::consCand(head1, result.getApprox(), _) and + result.getHead() = head2 and + result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + + override AccessPathApproxCons getApprox() { + result = TConsCons(head1, head2, len) or + result = TCons1(head1, len) + } + + override int length() { result = len } + + override string toString() { + if len = 2 + then result = "[" + head1.toString() + ", " + head2.toString() + "]" + else + result = "[" + head1.toString() + ", " + head2.toString() + ", ... (" + len.toString() + ")]" + } +} + +private class AccessPathCons1 extends AccessPath, TAccessPathCons1 { + private TypedContent head; + private int len; + + AccessPathCons1() { this = TAccessPathCons1(head, len) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { + Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { result = TCons1(head, len) } + + override int length() { result = len } + + override string toString() { + if len = 1 + then result = "[" + head.toString() + "]" + else result = "[" + head.toString() + ", ... (" + len.toString() + ")]" + } +} + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result } + + /** Gets the `FlowState` of this node. */ + FlowState getState() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getANonHiddenSuccessor() and + reach(this) and + reach(result) + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNodeImpl getASuccessorImpl(); + + private PathNodeImpl getASuccessorIfHidden() { + this.isHidden() and + result = this.getASuccessorImpl() + } + + final PathNodeImpl getANonHiddenSuccessor() { + result = this.getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + abstract NodeEx getNodeEx(); + + predicate isHidden() { + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) + } + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } + + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate directReach(PathNodeImpl n) { + n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor()) +} + +/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ +private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } + +/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNodeImpl n1, PathNode n2) { + n1.getANonHiddenSuccessor() = n2 and directReach(n2) +} + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { + Subpaths::subpaths(arg, par, ret, out) and + reach(arg) and + reach(par) and + reach(ret) and + reach(out) + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + NodeEx node; + FlowState state; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, ap, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbindConf(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = this.getSuccMid() + or + // a final step to a sink + result = this.getSuccMid().projectToSink() + } + + override predicate isSource() { + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + } + + predicate isAtSink() { + sinkNode(node, state, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getState() = state and + result.getConfiguration() = unbindConf(config) + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + NodeEx node; + FlowState state; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, state, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + override Configuration getConfiguration() { result = config } + + override PathNodeImpl getASuccessorImpl() { none() } + + override predicate isSource() { sourceNode(node, state, config) } +} + +private predicate pathNode( + PathNodeMid mid, NodeEx midnode, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, + Configuration conf, LocalCallContext localCC +) { + midnode = mid.getNodeEx() and + state = mid.getState() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + midnode.getEnclosingCallable()) and + ap = mid.getAp() +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +pragma[nomagic] +private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap +) { + exists(NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC | + pathNode(mid, midnode, state0, cc, sc, ap, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, true, _, conf, localCC) + ) + or + exists( + AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC + | + pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + exists(TypedContent tc | pathStoreStep(mid, node, state, ap.pop(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + exists(TypedContent tc | pathReadStep(mid, node, state, ap.push(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, state, _, cc, sc, _, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, state, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, state, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate pathReadStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + tc = ap0.getHead() and + Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, FlowState state, CallContext innercc, AccessPathApprox apa, + Configuration config +) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPathApprox apa, Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, state, innercc, apa, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private NodeEx getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config +) { + result.asNode() = kind.getAnOutNode(call) and + Stage4::revFlow(result, _, apa, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, FlowState state, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, state, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, ParameterPosition ppos, FlowState state, CallContext cc, DataFlowCall call, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(ArgNodeEx arg, ArgumentPosition apos | + pathNode(mid, arg, state, cc, _, ap, config, _) and + arg.asNode().(ArgNode).argumentOf(call, apos) and + apa = ap.getApprox() and + parameterMatch(ppos, apos) + ) +} + +pragma[nomagic] +private predicate parameterCand( + DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config +) { + exists(ParamNodeEx p | + Stage4::revFlow(p, _, apa, config) and + p.isParameterOf(callable, pos) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, AccessPath ap, Configuration config +) { + exists(AccessPathApprox apa | + pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, ap, + pragma[only_bind_into](apa), pragma[only_bind_into](config)) and + callable = resolveCall(call, outercc) and + parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) + ) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +pragma[nomagic] +private predicate pathIntoCallable( + PathNodeMid mid, ParamNodeEx p, FlowState state, CallContext outercc, CallContextCall innercc, + SummaryCtx sc, DataFlowCall call, Configuration config +) { + exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + ( + sc = TSummaryCtxSome(p, state, ap) + or + not exists(TSummaryCtxSome(p, state, ap)) and + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, + AccessPathApprox apa, Configuration config +) { + exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | + pathNode(mid, ret, state, cc, sc, ap, config, _) and + kind = ret.getKind() and + apa = ap.getApprox() and + pos = sc.getParameterPos() and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, state, innercc, sc, ap, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable( + PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, AccessPath ap +) { + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, state, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +private module Subpaths { + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths01( + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + exists(Configuration config | + pathThroughCallable(arg, out, pragma[only_bind_into](sout), _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, _, innercc, sc, _, config) and + paramFlowsThrough(kind, pragma[only_bind_into](sout), innercc, sc, + pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `sout`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths02( + PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and + out.asNode() = kind.getAnOutNode(_) + } + + pragma[nomagic] + private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple. + */ + pragma[nomagic] + private predicate subpaths03( + PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout + ) { + exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | + subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and + pathNode(ret, retnode, sout, innercc, sc, apout, unbindConf(getPathNodeConf(arg)), _) and + kind = retnode.getKind() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, _, n2, _, _, _, _, _) or + store(n1, _, n2, _, _) or + readSet(n1, _, n2, _) + ) + } + + pragma[nomagic] + private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getANonHiddenSuccessor() and + succNode = succ.getNodeEx() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { + exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | + pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and + subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and + not ret.isHidden() and + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() + ) + } + + /** + * Holds if `n` can reach a return node in a summarized subpath that can reach a sink. + */ + predicate retReach(PathNodeImpl n) { + exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) + or + exists(PathNodeImpl mid | + retReach(mid) and + n.getANonHiddenSuccessor() = mid and + not subpaths(_, mid, _, _) + ) + } +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.(PathNodeImpl).getNodeEx().asNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNodeEx().asNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private predicate finalStats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples +) { + fwd = true 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and + tuples = count(PathNode pn) + or + fwd = false 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and + tuples = count(PathNode pn | reach(pn)) +} + +/** + * INTERNAL: Only for debugging. + * + * Calculates per-stage metrics for data flow. + */ +predicate stageStats( + int n, string stage, int nodes, int fields, int conscand, int states, int tuples, + Configuration config +) { + stage = "1 Fwd" and + n = 10 and + Stage1::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "1 Rev" and + n = 15 and + Stage1::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Fwd" and + n = 20 and + Stage2::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Rev" and + n = 25 and + Stage2::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Fwd" and + n = 30 and + Stage3::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Rev" and + n = 35 and + Stage3::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Fwd" and + n = 40 and + Stage4::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Rev" and + n = 45 and + Stage4::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) + or + stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + additionalJumpStateStep(node1, _, node2, _, config) + or + // flow into callable + viableParamArgEx(_, node2, node1) + or + // flow out of a callable + viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) or config.isSource(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private predicate interestingCallableSink(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSink(n) or config.isSink(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSink(mid, config) and callableStep(c, mid, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { + interestingCallableSrc(c, config) or + interestingCallableSink(c, config) + } or + TCallableSrc() or + TCallableSink() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtSink(TCallableSink sink) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, pragma[only_bind_into](config)) and + ce2 = TCallable(c2, pragma[only_bind_into](config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + (config.isSource(n) or config.isSource(n, _)) and + ce2 = TCallable(getNodeEnclosingCallable(n), config) + ) + or + exists(Node n, Configuration config | + ce2 = TCallableSink() and + (config.isSink(n) or config.isSink(n, _)) and + ce1 = TCallable(getNodeEnclosingCallable(n), config) + ) + } + + private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) { + callableExtStepFwd(ce2, ce1) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSinkExt(TCallableExt c) = + shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private int distSink(DataFlowCallable c, Configuration config) { + result = distSinkExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + TypedContent getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private newtype TRevPartialAccessPath = + TRevPartialNil() or + TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `Content`s, but only the first + * element of the list and its length are tracked. + */ + private class RevPartialAccessPath extends TRevPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TRevPartialCons(result, _) } + + int len() { + this = TRevPartialNil() and result = 0 + or + this = TRevPartialCons(_, result) + } + } + + private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil { + override string toString() { result = "" } + } + + private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons { + override string toString() { + exists(Content c, int len | this = TRevPartialCons(c, len) | + if len = 1 + then result = "[" + c.toString() + "]" + else result = "[" + c.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private predicate relevantState(FlowState state) { + sourceNode(_, state, _) or + sinkNode(_, state, _) or + additionalLocalStateStep(_, state, _, _, _) or + additionalLocalStateStep(_, _, _, state, _) or + additionalJumpStateStep(_, state, _, _, _) or + additionalJumpStateStep(_, _, _, state, _) + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParamNodeEx p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TSummaryCtx3 = + TSummaryCtx3None() or + TSummaryCtx3Some(PartialAccessPath ap) + + private newtype TRevSummaryCtx1 = + TRevSummaryCtx1None() or + TRevSummaryCtx1Some(ReturnPosition pos) + + private newtype TRevSummaryCtx2 = + TRevSummaryCtx2None() or + TRevSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TRevSummaryCtx3 = + TRevSummaryCtx3None() or + TRevSummaryCtx3Some(RevPartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeFwd( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = TPartialNil(node.getDataFlowType()) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } or + TPartialPathNodeRev( + NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, TRevSummaryCtx3 sc3, + RevPartialAccessPath ap, Configuration config + ) { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() and + exists(config.explorationLimit()) + or + exists(PartialPathNodeRev mid | + revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and + not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() + ) + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and + if node.asNode() instanceof CastingNode + then compatibleTypes(node.getDataFlowType(), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + 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.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.getNodeEx().projectToNode() = result } + + FlowState getState() { none() } + + private NodeEx getNodeEx() { + result = this.(PartialPathNodeFwd).getNodeEx() or + result = this.(PartialPathNodeRev).getNodeEx() + } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + /** + * Gets the approximate distance to the nearest sink measured in number + * of interprocedural steps. + */ + int getSinkDistance() { + result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | + s = this.(PartialPathNodeFwd).getAp().toString() or + s = this.(PartialPathNodeRev).getAp().toString() + | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">" + } + + /** Holds if this is a source in a forward-flow path. */ + predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() } + + /** Holds if this is a sink in a reverse-flow path. */ + predicate isRevSink() { this.(PartialPathNodeRev).isSink() } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd { + NodeEx node; + FlowState state; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + TSummaryCtx3 sc3; + PartialAccessPath ap; + Configuration config; + + PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, state, cc, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TSummaryCtx3 getSummaryCtx3() { result = sc3 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeFwd getASuccessor() { + partialPathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx1(), result.getSummaryCtx2(), result.getSummaryCtx3(), result.getAp(), + result.getConfiguration()) + } + + predicate isSource() { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap instanceof TPartialNil + } + } + + private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev { + NodeEx node; + FlowState state; + TRevSummaryCtx1 sc1; + TRevSummaryCtx2 sc2; + TRevSummaryCtx3 sc3; + RevPartialAccessPath ap; + Configuration config; + + PartialPathNodeRev() { this = TPartialPathNodeRev(node, state, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + TRevSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TRevSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TRevSummaryCtx3 getSummaryCtx3() { result = sc3 } + + RevPartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeRev getASuccessor() { + revPartialPathStep(result, this.getNodeEx(), this.getState(), this.getSummaryCtx1(), + this.getSummaryCtx2(), this.getSummaryCtx3(), this.getAp(), this.getConfiguration()) + } + + predicate isSink() { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() + } + } + + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalLocalStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsFwd(ap, tc, ap0, config) + ) + or + partialPathIntoCallable(mid, node, state, _, cc, sc1, sc2, sc3, _, ap, config) + or + partialPathOutOfCallable(mid, node, state, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() + or + partialPathThroughCallable(mid, node, state, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + bindingset[result, i] + private int unbindInt(int i) { pragma[only_bind_out](i) = pragma[only_bind_out](result) } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node, + PartialAccessPath ap2 + ) { + exists(NodeEx midNode, DataFlowType contentType | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType, mid.getConfiguration()) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStoreStep(mid, ap1, tc, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc, + Configuration config + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and + ap.getHead() = tc and + pragma[only_bind_into](config) = mid.getConfiguration() and + cc = mid.getCallContext() + ) + } + + private predicate partialPathOutOfCallable0( + PartialPathNodeFwd mid, ReturnPosition pos, FlowState state, CallContext innercc, + PartialAccessPath ap, Configuration config + ) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, state, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, state, cc, ap, config) + | + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodeFwd mid, ParameterPosition ppos, FlowState state, CallContext cc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ArgNode arg, ArgumentPosition apos | + arg = mid.getNodeEx().asNode() and + state = mid.getState() and + cc = mid.getCallContext() and + arg.argumentOf(call, apos) and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, pos, state, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodeFwd mid, ParamNodeEx p, FlowState state, CallContext outercc, + CallContextCall innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ParameterPosition pos, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(state) and + sc3 = TSummaryCtx3Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, FlowState state, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid, RetNodeEx ret | + mid.getNodeEx() = ret and + kind = ret.getKind() and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3 | + partialPathIntoCallable(mid, _, _, cc, innercc, sc1, sc2, sc3, call, _, config) and + paramFlowsThroughInPartialPath(kind, state, innercc, sc1, sc2, sc3, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, state, cc, ap, config) and + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[nomagic] + private predicate revPartialPathStep( + PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, + TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config + ) { + localFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalLocalStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + jumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalJumpStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + revPartialPathReadStep(mid, _, _, node, ap) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(RevPartialAccessPath ap0, Content c | + revPartialPathStoreStep(mid, ap0, c, node, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsRev(ap, c, ap0, config) + ) + or + exists(ParamNodeEx p | + mid.getNodeEx() = p and + viableParamArgEx(_, p, node) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + or + exists(ReturnPosition pos | + revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap, config) and + pos = getReturnPosition(node.asNode()) + ) + or + revPartialPathThroughCallable(mid, node, state, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + pragma[inline] + private predicate revPartialPathReadStep( + PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node, + RevPartialAccessPath ap2 + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + read(node, c, midNode, mid.getConfiguration()) and + ap2.getHead() = c and + ap2.len() = unbindInt(ap1.len() + 1) + ) + } + + pragma[nomagic] + private predicate apConsRev( + RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeRev mid | + revPartialPathReadStep(mid, ap1, c, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathStoreStep( + PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config + ) { + exists(NodeEx midNode, TypedContent tc | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + store(node, tc, midNode, _, config) and + ap.getHead() = c and + config = mid.getConfiguration() and + tc.getContent() = c + ) + } + + pragma[nomagic] + private predicate revPartialPathIntoReturn( + PartialPathNodeRev mid, ReturnPosition pos, FlowState state, TRevSummaryCtx1Some sc1, + TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3, DataFlowCall call, RevPartialAccessPath ap, + Configuration config + ) { + exists(NodeEx out | + mid.getNodeEx() = out and + mid.getState() = state and + viableReturnPosOutEx(call, pos, out) and + sc1 = TRevSummaryCtx1Some(pos) and + sc2 = TRevSummaryCtx2Some(state) and + sc3 = TRevSummaryCtx3Some(ap) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathFlowsThrough( + ArgumentPosition apos, FlowState state, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, + TRevSummaryCtx3Some sc3, RevPartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos | + mid.getNodeEx() = p and + mid.getState() = state and + p.getPosition() = ppos and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable0( + DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, FlowState state, + RevPartialAccessPath ap, Configuration config + ) { + exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3 | + revPartialPathIntoReturn(mid, _, _, sc1, sc2, sc3, call, _, config) and + revPartialPathFlowsThrough(pos, state, sc1, sc2, sc3, ap, config) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable( + PartialPathNodeRev mid, ArgNodeEx node, FlowState state, RevPartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ArgumentPosition pos | + revPartialPathThroughCallable0(call, mid, pos, state, ap, config) and + node.asNode().(ArgNode).argumentOf(call, pos) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + source.isFwdSource() and + node = source.getASuccessor+() +} + +private predicate revPartialFlow( + PartialPathNode node, PartialPathNode sink, Configuration configuration +) { + sink.getConfiguration() = configuration and + sink.isRevSink() and + node.getASuccessor+() = sink +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll new file mode 100644 index 00000000000..468f8640a78 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -0,0 +1,4450 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. This file exists in several identical + * copies, allowing queries to use multiple `Configuration` classes that depend + * on each other without introducing mutual recursion among those configurations. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ```ql + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(Node source) { none() } + + /** + * Holds if `source` is a relevant data flow source with the given initial + * `state`. + */ + predicate isSource(Node source, FlowState state) { none() } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(Node sink) { none() } + + /** + * Holds if `sink` is a relevant data flow sink accepting `state`. + */ + predicate isSink(Node source, FlowState state) { none() } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** + * Holds if data flow through `node` is prohibited when the flow state is + * `state`. + */ + predicate isBarrier(Node node, FlowState state) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead. + * + * Holds if data flow through nodes guarded by `guard` is prohibited when + * the flow state is `state` + */ + deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) { + none() + } + + /** + * Holds if an arbitrary number of implicit read steps of content `c` may be + * taken at `node`. + */ + predicate allowImplicitRead(Node node, ContentSet c) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` + * measured in approximate number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } + + /** + * Holds if there is a partial data flow path from `node` to `sink`. The + * approximate distance between `node` and the closest sink is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards source definitions. + * + * This predicate is intended for data-flow exploration and debugging and may + * perform poorly if the number of sinks is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + * + * Note that reverse flow has slightly lower precision than the corresponding + * forward flow, as reverse flow disregards type pruning among other features. + */ + final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) { + revPartialFlow(node, sink, this) and + dist = node.getSinkDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSource(n, _)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n | this.isSink(n, _)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0 + or + super.hasFlow(source, sink) + } +} + +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 class ArgNodeEx extends NodeEx { + ArgNodeEx() { this.asNode() instanceof ArgNode } +} + +private class ParamNodeEx extends NodeEx { + ParamNodeEx() { this.asNode() instanceof ParamNode } + + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + this.asNode().(ParamNode).isParameterOf(c, pos) + } + + ParameterPosition getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } +} + +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) + | + config.isSource(n) or config.isSource(n, _) + ) +} + +private predicate outBarrier(NodeEx node, Configuration config) { + exists(Node n | + node.asNode() = n and + config.isBarrierOut(n) + | + config.isSink(n) or config.isSink(n, _) + ) +} + +/** A bridge class to access the deprecated `isBarrierGuard`. */ +private class BarrierGuardGuardedNodeBridge extends Unit { + abstract predicate guardedNode(Node n, Configuration config); + + abstract predicate guardedNode(Node n, FlowState state, Configuration config); +} + +private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge { + deprecated override predicate guardedNode(Node n, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g) and + n = g.getAGuardedNode() + ) + } + + deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) { + exists(BarrierGuard g | + config.isBarrierGuard(g, state) and + n = g.getAGuardedNode() + ) + } +} + +pragma[nomagic] +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) and + not config.isSource(n, _) + or + config.isBarrierOut(n) and + not config.isSink(n) and + not config.isSink(n, _) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config) + ) +} + +pragma[nomagic] +private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) { + exists(Node n | node.asNode() = n | + config.isBarrier(n, state) + or + any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config) + ) +} + +pragma[nomagic] +private predicate sourceNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSource(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSource(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +pragma[nomagic] +private predicate sinkNode(NodeEx node, FlowState state, Configuration config) { + ( + config.isSink(node.asNode()) and state instanceof FlowStateEmpty + or + config.isSink(node.asNode(), state) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) +} + +/** Provides the relevant barriers for a step from `node1` to `node2`. */ +pragma[inline] +private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) { + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.asNode() = n and + node2.isImplicitReadNode(n, false) and + not fullBarrier(node1, config) + ) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) + ) + or + exists(Node n | + config.allowImplicitRead(n, _) and + node1.isImplicitReadNode(n, true) and + node2.asNode() = n and + not fullBarrier(node2, config) + ) +} + +private predicate additionalLocalStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) + ) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration config) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate additionalJumpStateStep( + NodeEx node1, FlowState s1, NodeEx node2, FlowState s2, Configuration config +) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and + getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and + stepFilter(node1, node2, config) and + not stateBarrier(node1, s1, config) and + not stateBarrier(node2, s2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) +} + +pragma[nomagic] +private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and + stepFilter(node1, node2, config) + or + exists(Node n | + node2.isImplicitReadNode(n, true) and + node1.isImplicitReadNode(n, _) and + config.allowImplicitRead(n, c) + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { + exists(ContentSet cs | + readSet(node1, cs, node2, config) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate clearsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + clearsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +bindingset[c] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + +pragma[nomagic] +private predicate store( + NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config +) { + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and + read(_, tc.getContent(), _, config) and + stepFilter(node1, node2, 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()) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private module Stage1 implements StageSig { + class ApApprox = Unit; + + class Ap = Unit; + + class ApOption = Unit; + + class Cc = boolean; + + /* Begin: Stage 1 logic. */ + /** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `cc` records whether the node is reached through an + * argument in a call. + */ + predicate fwdFlow(NodeEx node, Cc cc, Configuration config) { + sourceNode(node, _, config) and + if hasSourceCallCtx(config) then cc = true else cc = false + or + exists(NodeEx mid | fwdFlow(mid, cc, config) | + localFlowStep(mid, node, config) or + additionalLocalFlowStep(mid, node, config) or + additionalLocalStateStep(mid, _, node, _, config) + ) + or + exists(NodeEx mid | fwdFlow(mid, _, config) and cc = false | + jumpStep(mid, node, config) or + additionalJumpStep(mid, node, config) or + additionalJumpStateStep(mid, _, node, _, config) + ) + or + // store + exists(NodeEx mid | + useFieldFlow(config) and + fwdFlow(mid, cc, config) and + store(mid, _, node, _, config) + ) + or + // read + exists(ContentSet c | + fwdFlowReadSet(c, node, cc, config) and + fwdFlowConsCandSet(c, _, config) + ) + or + // flow into a callable + exists(NodeEx arg | + fwdFlow(arg, _, config) and + viableParamArgEx(_, node, arg) and + cc = true and + not fullBarrier(node, config) + ) + or + // flow out of a callable + exists(DataFlowCall call | + fwdFlowOut(call, node, false, config) and + cc = false + or + fwdFlowOutFromArg(call, node, config) and + fwdFlowIsEntered(call, cc, config) + ) + } + + private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) } + + pragma[nomagic] + private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) { + exists(NodeEx mid | + fwdFlow(mid, cc, config) and + readSet(mid, c, node, config) + ) + } + + /** + * Holds if `c` is the target of a store in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, TypedContent tc | + not fullBarrier(node, config) and + useFieldFlow(config) and + fwdFlow(mid, _, config) and + store(mid, tc, node, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `cs` may be interpreted in a read as the target of some store + * into `c`, in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) { + fwdFlowConsCand(c, config) and + c = cs.getAReadContent() + } + + pragma[nomagic] + private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) { + exists(RetNodeEx ret | + fwdFlow(ret, cc, config) and + ret.getReturnPosition() = pos + ) + } + + pragma[nomagic] + private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) { + exists(ReturnPosition pos | + fwdFlowReturnPosition(pos, cc, config) and + viableReturnPosOutEx(call, pos, out) and + not fullBarrier(out, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg(DataFlowCall call, NodeEx out, Configuration config) { + fwdFlowOut(call, out, true, config) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { + exists(ArgNodeEx arg | + fwdFlow(arg, cc, config) and + viableParamArgEx(call, _, arg) + ) + } + + private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1 | + additionalLocalStateStep(node1, state1, _, state2, config) or + additionalJumpStateStep(node1, state1, _, state2, config) + | + fwdFlow(node1, config) + ) + } + + private predicate fwdFlowState(FlowState state, Configuration config) { + sourceNode(_, state, config) + or + exists(FlowState state0 | + fwdFlowState(state0, config) and + stateStepFwd(state0, state, config) + ) + } + + /** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ + pragma[nomagic] + predicate revFlow(NodeEx node, boolean toReturn, Configuration config) { + revFlow0(node, toReturn, config) and + fwdFlow(node, config) + } + + pragma[nomagic] + private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { + exists(FlowState state | + fwdFlow(node, pragma[only_bind_into](config)) and + sinkNode(node, state, config) and + fwdFlowState(state, pragma[only_bind_into](config)) and + if hasSinkCallCtx(config) then toReturn = true else toReturn = false + ) + or + exists(NodeEx mid | revFlow(mid, toReturn, config) | + localFlowStep(node, mid, config) or + additionalLocalFlowStep(node, mid, config) or + additionalLocalStateStep(node, _, mid, _, config) + ) + or + exists(NodeEx mid | revFlow(mid, _, config) and toReturn = false | + jumpStep(node, mid, config) or + additionalJumpStep(node, mid, config) or + additionalJumpStateStep(node, _, mid, _, config) + ) + or + // store + exists(Content c | + revFlowStore(c, node, toReturn, config) and + revFlowConsCand(c, config) + ) + or + // read + exists(NodeEx mid, ContentSet c | + readSet(node, c, mid, config) and + fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and + revFlow(mid, toReturn, pragma[only_bind_into](config)) + ) + or + // flow into a callable + exists(DataFlowCall call | + revFlowIn(call, node, false, config) and + toReturn = false + or + revFlowInToReturn(call, node, config) and + revFlowIsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + revFlowOut(pos, config) and + node.(RetNodeEx).getReturnPosition() = pos and + toReturn = true + ) + } + + /** + * Holds if `c` is the target of a read in the flow covered by `revFlow`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Content c, Configuration config) { + exists(NodeEx mid, NodeEx node, ContentSet cs | + fwdFlow(node, pragma[only_bind_into](config)) and + readSet(node, cs, mid, config) and + fwdFlowConsCandSet(cs, 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, 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, _, config) and + c = tc.getContent() + ) + } + + /** + * Holds if `c` is the target of both a read and a store in the flow covered + * by `revFlow`. + */ + pragma[nomagic] + predicate revFlowIsReadAndStored(Content c, Configuration conf) { + revFlowConsCand(c, conf) and + revFlowStore(c, _, _, conf) + } + + pragma[nomagic] + predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config + ) { + fwdFlowReturnPosition(pos, _, config) and + viableReturnPosOutEx(call, pos, out) + } + + pragma[nomagic] + private predicate revFlowOut(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, NodeEx out | + revFlow(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) + } + + pragma[nomagic] + predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config + ) { + viableParamArgEx(call, p, arg) and + fwdFlow(arg, config) + } + + pragma[nomagic] + 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, ArgNodeEx arg, Configuration config) { + revFlowIn(call, arg, true, config) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(NodeEx out | + revFlow(out, toReturn, config) and + fwdFlowOutFromArg(call, out, config) + ) + } + + private predicate stateStepRev(FlowState state1, FlowState state2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + additionalLocalStateStep(node1, state1, node2, state2, config) or + additionalJumpStateStep(node1, state1, node2, state2, config) + | + revFlow(node1, _, pragma[only_bind_into](config)) and + revFlow(node2, _, pragma[only_bind_into](config)) and + fwdFlowState(state1, pragma[only_bind_into](config)) and + fwdFlowState(state2, pragma[only_bind_into](config)) + ) + } + + predicate revFlowState(FlowState state, Configuration config) { + exists(NodeEx node | + sinkNode(node, state, config) and + revFlow(node, _, pragma[only_bind_into](config)) and + fwdFlowState(state, pragma[only_bind_into](config)) + ) + or + exists(FlowState state0 | + revFlowState(state0, config) and + stateStepRev(state, state0, config) + ) + } + + pragma[nomagic] + predicate storeStepCand( + 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, config) and + c = tc.getContent() and + exists(ap1) + ) + } + + pragma[nomagic] + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + read(n1, c, n2, pragma[only_bind_into](config)) and + revFlow(n2, pragma[only_bind_into](config)) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, _, pragma[only_bind_into](config)) and + exists(state) and + exists(ap) + } + + private predicate throughFlowNodeCand(NodeEx node, Configuration config) { + revFlow(node, true, config) and + fwdFlow(node, true, config) and + not inBarrier(node, config) and + not outBarrier(node, config) + } + + /** Holds if flow may return from `callable`. */ + pragma[nomagic] + private predicate returnFlowCallableNodeCand( + DataFlowCallable callable, ReturnKindExt kind, Configuration config + ) { + exists(RetNodeEx ret | + throughFlowNodeCand(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) + } + + /** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ + pragma[nomagic] + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand(p, config) and + returnFlowCallableNodeCand(c, kind, config) and + p.getEnclosingCallable() = c and + exists(ap) and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists(ArgNodeEx arg, boolean toReturn | + revFlow(arg, toReturn, config) and + revFlowInToReturn(call, arg, config) and + revFlowIsReturned(call, toReturn, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true and + nodes = count(NodeEx node | fwdFlow(node, config)) and + fields = count(Content f0 | fwdFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | fwdFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | fwdFlow(n, b, config)) + or + fwd = false and + nodes = count(NodeEx node | revFlow(node, _, config)) and + fields = count(Content f0 | revFlowConsCand(f0, config)) and + conscand = -1 and + states = count(FlowState state | revFlowState(state, config)) and + tuples = count(NodeEx n, boolean b | revFlow(n, b, config)) + } + /* End: Stage 1 logic. */ +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, Configuration config) { + Stage1::revFlow(node2, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +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, NodeEx out, Configuration config +) { + Stage1::revFlow(out, config) and + Stage1::viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config +) { + viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and + Stage1::revFlow(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config +) { + Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and + Stage1::revFlow(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + Stage1::revFlow(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(NodeEx n1, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(NodeEx n2, Configuration conf) { + result = + strictcount(NodeEx n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +private signature module StageSig { + class Ap; + + predicate revFlow(NodeEx node, Configuration config); + + bindingset[node, state, config] + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); + + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); + + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ); + + predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config); +} + +private module MkStage { + class ApApprox = PrevStage::Ap; + + signature module StageParam { + class Ap; + + class ApNil extends Ap; + + bindingset[result, ap] + ApApprox getApprox(Ap ap); + + ApNil getApNil(NodeEx node); + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail); + + Content getHeadContent(Ap ap); + + class ApOption; + + ApOption apNone(); + + ApOption apSome(Ap ap); + + class Cc; + + class CcCall extends Cc; + + // TODO: member predicate on CcCall + predicate matchesCall(CcCall cc, DataFlowCall call); + + class CcNoCall extends Cc; + + Cc ccNone(); + + CcCall ccSomeCall(); + + class LocalCc; + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc); + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc); + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc); + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ); + + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config + ); + + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config + ); + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config); + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType); + } + + module Stage implements StageSig { + import Param + + /* Begin: Stage logic. */ + bindingset[result, apa] + private ApApprox unbindApa(ApApprox apa) { + pragma[only_bind_out](apa) = pragma[only_bind_out](result) + } + + pragma[nomagic] + private predicate flowThroughOutOfCall( + DataFlowCall call, CcCall ccc, 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(_, ret.getEnclosingCallable(), _, + pragma[only_bind_into](config)) and + matchesCall(ccc, call) + } + + /** + * Holds if `node` is reachable with access path `ap` from a source in the + * configuration `config`. + * + * The call context `cc` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ + pragma[nomagic] + predicate fwdFlow( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + fwdFlow0(node, state, cc, argAp, ap, config) and + PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and + filter(node, state, ap, config) + } + + pragma[nomagic] + private predicate fwdFlow0( + NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + sourceNode(node, state, config) and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and + argAp = apNone() and + ap = getApNil(node) + or + exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | + fwdFlow(mid, state0, cc, argAp, ap0, config) and + localCc = getLocalCc(mid, cc) + | + localStep(mid, state0, node, state, true, _, config, localCc) and + ap = ap0 + or + localStep(mid, state0, node, state, false, ap, config, localCc) and + ap0 instanceof ApNil + ) + or + exists(NodeEx mid | + fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + jumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() + ) + or + exists(NodeEx mid, ApNil nil | + fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStep(mid, node, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and + additionalJumpStateStep(mid, state0, node, state, config) and + cc = ccNone() and + argAp = apNone() and + ap = getApNil(node) + ) + or + // store + exists(TypedContent tc, Ap ap0 | + fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and + ap = apCons(tc, ap0) + ) + or + // read + exists(Ap ap0, Content c | + fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and + fwdFlowConsCand(ap0, c, ap, config) + ) + or + // flow into a callable + exists(ApApprox apa | + fwdFlowIn(_, node, state, _, cc, _, ap, config) and + apa = getApprox(ap) and + if PrevStage::parameterMayFlowThrough(node, _, apa, config) + then argAp = apSome(ap) + else argAp = apNone() + ) + or + // flow out of a callable + fwdFlowOutNotFromArg(node, state, cc, argAp, ap, config) + or + exists(DataFlowCall call, Ap argAp0 | + fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and + fwdFlowIsEntered(call, cc, argAp, argAp0, config) + ) + } + + pragma[nomagic] + private predicate fwdFlowStore( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + exists(DataFlowType contentType | + fwdFlow(node1, state, cc, argAp, ap1, config) and + PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and + typecheckStore(ap1, contentType) + ) + } + + /** + * Holds if forward flow with access path `tail` reaches a store of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(TypedContent tc | + fwdFlowStore(_, tail, tc, _, _, _, _, config) and + tc.getContent() = c and + cons = apCons(tc, tail) + ) + } + + pragma[nomagic] + private predicate fwdFlowRead( + Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, + Configuration config + ) { + fwdFlow(node1, state, cc, argAp, ap, config) and + PrevStage::readStepCand(node1, c, node2, config) and + getHeadContent(ap) = c + } + + pragma[nomagic] + private predicate fwdFlowIn( + DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, + Ap ap, Configuration config + ) { + exists(ArgNodeEx arg, boolean allowsFieldFlow | + fwdFlow(arg, state, outercc, argAp, ap, config) and + flowIntoCall(call, arg, p, allowsFieldFlow, config) and + innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutNotFromArg( + NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config + ) { + exists( + DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, + DataFlowCallable inner + | + fwdFlow(ret, state, innercc, argAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + inner = ret.getEnclosingCallable() and + ccOut = getCallContextReturn(inner, call, innercc) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate fwdFlowOutFromArg( + DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc | + fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and + flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an argument to `call` is reached in the flow covered by `fwdFlow` + * and data might flow through the target callable and back out at `call`. + */ + pragma[nomagic] + private predicate fwdFlowIsEntered( + DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p | + fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and + PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) + ) + } + + pragma[nomagic] + private predicate storeStepFwd( + 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( + 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, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, + pragma[only_bind_into](config)) and + fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate flowThroughIntoCall( + 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 + PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and + callMayFlowThroughFwd(call, pragma[only_bind_into](config)) + } + + pragma[nomagic] + private predicate returnNodeMayFlowThrough( + RetNodeEx ret, FlowState state, Ap ap, Configuration config + ) { + fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config) + } + + /** + * Holds if `node` with access path `ap` is part of a path from a source to a + * sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from the + * enclosing callable in order to reach a sink, and if so, `returnAp` records + * the access path of the returned value. + */ + pragma[nomagic] + predicate revFlow( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + revFlow0(node, state, toReturn, returnAp, ap, config) and + fwdFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + private predicate revFlow0( + NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + fwdFlow(node, state, _, _, ap, config) and + sinkNode(node, state, config) and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and + returnAp = apNone() and + ap instanceof ApNil + or + exists(NodeEx mid, FlowState state0 | + localStep(node, state, mid, state0, true, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, ap, config) + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and + localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and + revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and + ap instanceof ApNil + ) + or + exists(NodeEx mid | + jumpStep(node, mid, config) and + revFlow(mid, state, _, _, ap, config) and + toReturn = false and + returnAp = apNone() + ) + or + 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), state, _, _, nil, pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + exists(NodeEx mid, FlowState state0, ApNil nil | + fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and + additionalJumpStateStep(node, state, mid, state0, config) and + revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, + pragma[only_bind_into](config)) and + toReturn = false and + returnAp = apNone() and + ap instanceof ApNil + ) + or + // store + exists(Ap ap0, Content c | + revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and + revFlowConsCand(ap0, c, ap, config) + ) + or + // read + exists(NodeEx mid, Ap ap0 | + revFlow(mid, state, toReturn, returnAp, ap0, config) and + readStepFwd(node, ap, _, mid, ap0, config) + ) + or + // flow into a callable + revFlowInNotToReturn(node, state, returnAp, ap, config) and + toReturn = false + or + exists(DataFlowCall call, Ap returnAp0 | + revFlowInToReturn(call, node, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + or + // flow out of a callable + revFlowOut(_, node, state, _, _, ap, config) and + toReturn = true and + if returnNodeMayFlowThrough(node, state, ap, config) + then returnAp = apSome(ap) + else returnAp = apNone() + } + + pragma[nomagic] + private predicate revFlowStore( + Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, + boolean toReturn, ApOption returnAp, Configuration config + ) { + revFlow(mid, state, toReturn, returnAp, ap0, config) and + storeStepFwd(node, ap, tc, mid, ap0, config) and + tc.getContent() = c + } + + /** + * Holds if reverse flow with access path `tail` reaches a read of `c` + * resulting in access path `cons`. + */ + pragma[nomagic] + private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { + exists(NodeEx mid, Ap tail0 | + revFlow(mid, _, _, _, tail, config) and + tail = pragma[only_bind_into](tail0) and + readStepFwd(_, cons, c, mid, tail0, config) + ) + } + + pragma[nomagic] + private predicate revFlowOut( + DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, + Configuration config + ) { + exists(NodeEx out, boolean allowsFieldFlow | + revFlow(out, state, toReturn, returnAp, ap, config) and + flowOutOfCall(call, ret, out, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInNotToReturn( + ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, false, returnAp, ap, config) and + flowIntoCall(_, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + pragma[nomagic] + private predicate revFlowInToReturn( + DataFlowCall call, ArgNodeEx arg, FlowState state, Ap returnAp, Ap ap, Configuration config + ) { + exists(ParamNodeEx p, boolean allowsFieldFlow | + revFlow(p, state, true, apSome(returnAp), ap, config) and + flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } + + /** + * Holds if an output from `call` is reached in the flow covered by `revFlow` + * and data might flow through the target callable resulting in reverse flow + * reaching an argument of `call`. + */ + pragma[nomagic] + private predicate revFlowIsReturned( + DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config + ) { + exists(RetNodeEx ret, FlowState state, CcCall ccc | + revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and + fwdFlow(ret, state, ccc, apSome(_), ap, config) and + matchesCall(ccc, call) + ) + } + + pragma[nomagic] + predicate storeStepCand( + NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, + Configuration config + ) { + exists(Ap ap2, Content c | + PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and + revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and + revFlowConsCand(ap2, c, ap1, 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 + revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _, _, + pragma[only_bind_into](config)) + ) + } + + predicate revFlow(NodeEx node, FlowState state, Configuration config) { + revFlow(node, state, _, _, _, config) + } + + predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, _, _, ap, config) + } + + pragma[nomagic] + predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } + + // use an alias as a workaround for bad functionality-induced joins + pragma[nomagic] + predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) { + revFlow(node, state, ap, config) + } + + private predicate fwdConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepFwd(_, ap, tc, _, _, config) + } + + private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) { + storeStepCand(_, ap, tc, _, _, config) + } + + private predicate validAp(Ap ap, Configuration config) { + revFlow(_, _, _, _, ap, config) and ap instanceof ApNil + or + exists(TypedContent head, Ap tail | + consCand(head, tail, config) and + ap = apCons(head, tail) + ) + } + + predicate consCand(TypedContent tc, Ap ap, Configuration config) { + revConsCand(tc, ap, config) and + validAp(ap, config) + } + + pragma[noinline] + private predicate parameterFlow( + ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config + ) { + revFlow(p, _, true, apSome(ap0), ap, config) and + c = p.getEnclosingCallable() + } + + predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { + exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | + parameterFlow(p, ap, ap0, c, config) and + c = ret.getEnclosingCallable() and + revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), + pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and + fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and + kind = ret.getKind() and + p.getPosition() = pos and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) + ) + } + + pragma[nomagic] + predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { + exists( + Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap + | + revFlow(arg, state, toReturn, returnAp, ap, config) and + revFlowInToReturn(call, arg, state, returnAp0, ap, config) and + revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + } + + predicate stats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config + ) { + fwd = true 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 + states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | + fwdFlow(n, state, cc, argAp, ap, config) + ) + or + fwd = false 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 + states = count(FlowState state | revFlow(_, state, _, _, _, config)) and + tuples = + count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | + revFlow(n, state, b, retAp, ap, config) + ) + } + /* End: Stage logic. */ + } +} + +private module BooleanCallContext { + class Cc extends boolean { + Cc() { this in [true, false] } + } + + class CcCall extends Cc { + CcCall() { this = true } + } + + /** Holds if the call context may be `call`. */ + predicate matchesCall(CcCall cc, DataFlowCall call) { any() } + + class CcNoCall extends Cc { + CcNoCall() { this = false } + } + + Cc ccNone() { result = false } + + CcCall ccSomeCall() { result = true } + + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + + bindingset[call, c, innercc] + CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } +} + +private module Level1CallContext { + class Cc = CallContext; + + class CcCall = CallContextCall; + + pragma[inline] + predicate matchesCall(CcCall cc, DataFlowCall call) { cc.matchesCall(call) } + + class CcNoCall = CallContextNoCall; + + Cc ccNone() { result instanceof CallContextAny } + + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + + module NoLocalCallContext { + class LocalCc = Unit; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { any() } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } + } + + module LocalCallContext { + class LocalCc = LocalCallContext; + + bindingset[node, cc] + LocalCc getLocalCc(NodeEx node, Cc cc) { + result = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + node.getEnclosingCallable()) + } + + bindingset[call, c, outercc] + CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSite(call, c) then result = TSpecificCall(call) else result = TSomeCall() + } + } + + bindingset[call, c, innercc] + 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() + } +} + +private module Stage2Param implements MkStage::StageParam { + private module PrevStage = Stage1; + + class Ap extends boolean { + Ap() { this in [true, false] } + } + + class ApNil extends Ap { + ApNil() { this = false } + } + + bindingset[result, ap] + PrevStage::Ap getApprox(Ap ap) { any() } + + ApNil getApNil(NodeEx node) { Stage1::revFlow(node, _) and exists(result) } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) } + + pragma[inline] + Content getHeadContent(Ap ap) { exists(result) and ap = true } + + class ApOption = BooleanOption; + + ApOption apNone() { result = TBooleanNone() } + + ApOption apSome(Ap ap) { result = TBooleanSome(ap) } + + import Level1CallContext + import NoLocalCallContext + + bindingset[node1, state1, config] + bindingset[node2, state2, config] + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + ( + preservesValue = true and + localFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 + or + preservesValue = false and + additionalLocalStateStep(node1, state1, node2, state2, config) + ) and + exists(ap) and + exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand1/5; + + predicate flowIntoCall = flowIntoCallNodeCand1/5; + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + PrevStage::revFlowState(state, pragma[only_bind_into](config)) and + exists(ap) and + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage2 implements StageSig { + import MkStage::Stage +} + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + 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 + Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) +} + +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 NodeEx { + FlowCheckNode() { + castNode(this.asNode()) or + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) + } + } + + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) { + Stage2::revFlow(node, state, config) and + ( + sourceNode(node, state, config) + or + jumpStep(_, node, config) + or + additionalJumpStep(_, node, config) + or + additionalJumpStateStep(_, _, node, state, config) + or + node instanceof ParamNodeEx + or + node.asNode() instanceof OutNodeExt + or + Stage2::storeStepCand(_, _, _, node, _, config) + or + Stage2::readStepCand(_, _, node, config) + or + node instanceof FlowCheckNode + or + exists(FlowState s | + additionalLocalStateStep(_, s, node, state, config) and + s != state + ) + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(NodeEx node, FlowState state, Configuration config) { + exists(NodeEx next | Stage2::revFlow(next, state, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + Stage2::storeStepCand(node, _, _, next, _, config) or + Stage2::readStepCand(node, _, next, config) + ) + or + exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) | + additionalJumpStateStep(node, state, next, s, config) + or + additionalLocalStateStep(node, state, next, s, config) and + s != state + ) + or + Stage2::revFlow(node, state, config) and + node instanceof FlowCheckNode + or + sinkNode(node, state, config) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, Configuration config + ) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + state1 = state2 and + Stage2::revFlow(node1, pragma[only_bind_into](state1), false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, pragma[only_bind_into](state2), false, + pragma[only_bind_into](config)) + or + additionalLocalStateStep(node1, state1, node2, state2, config) and + Stage2::revFlow(node1, state1, false, pragma[only_bind_into](config)) and + Stage2::revFlowAlias(node2, state2, false, pragma[only_bind_into](config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t, + Configuration config, LocalCallContext cc + ) { + not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = node1.getDataFlowType() and // irrelevant dummy value + Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config)) + or + additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and + preservesValue = false and + t = node2.getDataFlowType() + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) + or + exists(NodeEx mid | + localFlowStepPlus(node1, pragma[only_bind_into](state), 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](state), pragma[only_bind_into](config)) + ) + or + exists(NodeEx mid | + localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and + additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and + not mid instanceof FlowCheckNode and + preservesValue = false and + t = node2.getDataFlowType() + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + AccessPathFrontNil apf, Configuration config, LocalCallContext callContext + ) { + localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, state1, config) and + state1 = state2 + or + additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and + state1 != state2 and + preservesValue = false and + apf = TFrontNil(node2.getDataFlowType()) and + callContext.relevantFor(node1.getEnclosingCallable()) and + not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | + isUnreachableInCallCached(node1.asNode(), call) or + isUnreachableInCallCached(node2.asNode(), call) + ) + } +} + +private import LocalFlowBigStep + +private module Stage3Param implements MkStage::StageParam { + private module PrevStage = Stage2; + + class Ap = AccessPathFront; + + class ApNil = AccessPathFrontNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathFrontOption; + + ApOption apNone() { result = TAccessPathFrontNone() } + + ApOption apSome(Ap ap) { result = TAccessPathFrontSome(ap) } + + import BooleanCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) + } + + predicate flowOutOfCall = flowOutOfCallNodeCand2/5; + + predicate flowIntoCall = flowIntoCallNodeCand2/5; + + pragma[nomagic] + private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { + PrevStage::revFlow(node, config) and + clearsContentCached(node.asNode(), c) + } + + pragma[nomagic] + private predicate clearContent(NodeEx node, Content c, Configuration config) { + exists(ContentSet cs | + PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and + c = cs.getAReadContent() and + clearSet(node, cs, pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + private predicate clear(NodeEx node, Ap ap, Configuration config) { + clearContent(node, ap.getHead().getContent(), config) + } + + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + + pragma[nomagic] + private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { + exists(state) and + exists(config) and + not clear(node, ap, config) and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) + } + + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { + // We need to typecheck stores here, since reverse flow through a getter + // might have a different type here compared to inside the getter. + compatibleTypes(ap.getType(), contentType) + } +} + +private module Stage3 implements StageSig { + import MkStage::Stage +} + +/** + * Holds if `argApf` is recorded as the summary context for flow reaching `node` + * and remains relevant for the following pruning stage. + */ +private predicate flowCandSummaryCtx( + NodeEx node, FlowState state, AccessPathFront argApf, Configuration config +) { + exists(AccessPathFront apf | + Stage3::revFlow(node, state, true, _, apf, config) and + Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) + ) +} + +/** + * Holds if a length 2 access path approximation with the head `tc` is expected + * to be expensive. + */ +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(NodeEx n, FlowState state | + Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + or + flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) + ) and + accessPathApproxCostLimits(apLimit, tupleLimit) and + apLimit < tails and + tupleLimit < (tails - 1) * nodes and + not tc.forceHighPrecision() + ) +} + +private newtype TAccessPathApprox = + TNil(DataFlowType t) or + TConsNil(TypedContent tc, DataFlowType t) { + Stage3::consCand(tc, TFrontNil(t), _) and + not expensiveLen2unfolding(tc, _) + } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + Stage3::consCand(tc1, TFrontHead(tc2), _) and + len in [2 .. accessPathLimit()] and + not expensiveLen2unfolding(tc1, _) + } or + TCons1(TypedContent tc, int len) { + len in [1 .. accessPathLimit()] and + expensiveLen2unfolding(tc, _) + } + +/** + * Conceptually a list of `TypedContent`s followed by a `DataFlowType`, but only + * the first two elements of the list and its length are tracked. If data flows + * from a source to a given node with a given `AccessPathApprox`, this indicates + * the sequence of dereference operations needed to get from the value in the node + * to the tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPathApprox extends TAccessPathApprox { + abstract string toString(); + + abstract TypedContent getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** Gets the access path obtained by popping `head` from this path, if any. */ + abstract AccessPathApprox pop(TypedContent head); +} + +private class AccessPathApproxNil extends AccessPathApprox, TNil { + private DataFlowType t; + + AccessPathApproxNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override TypedContent getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override AccessPathApprox pop(TypedContent head) { none() } +} + +abstract private class AccessPathApproxCons extends AccessPathApprox { } + +private class AccessPathApproxConsNil extends AccessPathApproxCons, TConsNil { + private TypedContent tc; + private DataFlowType t; + + AccessPathApproxConsNil() { this = TConsNil(tc, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override TypedContent getHead() { result = tc } + + override int len() { result = 1 } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { head = tc and result = TNil(t) } +} + +private class AccessPathApproxConsCons extends AccessPathApproxCons, TConsCons { + private TypedContent tc1; + private TypedContent tc2; + private int len; + + AccessPathApproxConsCons() { this = TConsCons(tc1, tc2, len) } + + override string toString() { + if len = 2 + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc1 } + + override int len() { result = len } + + override DataFlowType getType() { result = tc1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc1) } + + override AccessPathApprox pop(TypedContent head) { + head = tc1 and + ( + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + } +} + +private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 { + private TypedContent tc; + private int len; + + AccessPathApproxCons1() { this = TCons1(tc, len) } + + override string toString() { + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + } + + override TypedContent getHead() { result = tc } + + override int len() { result = len } + + override DataFlowType getType() { result = tc.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(tc) } + + override AccessPathApprox pop(TypedContent head) { + head = tc and + ( + exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | + result = TConsCons(tc2, _, len - 1) + or + len = 2 and + result = TConsNil(tc2, _) + or + result = TCons1(tc2, len - 1) + ) + or + exists(DataFlowType t | + len = 1 and + Stage3::consCand(tc, TFrontNil(t), _) and + result = TNil(t) + ) + ) + } +} + +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPathApprox pop(TypedContent tc, AccessPathApprox apa) { result = apa.pop(tc) } + +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPathApprox push(TypedContent tc, AccessPathApprox apa) { apa = pop(tc, result) } + +private newtype TAccessPathApproxOption = + TAccessPathApproxNone() or + TAccessPathApproxSome(AccessPathApprox apa) + +private class AccessPathApproxOption extends TAccessPathApproxOption { + string toString() { + this = TAccessPathApproxNone() and result = "" + or + this = TAccessPathApproxSome(any(AccessPathApprox apa | result = apa.toString())) + } +} + +private module Stage4Param implements MkStage::StageParam { + private module PrevStage = Stage3; + + class Ap = AccessPathApprox; + + class ApNil = AccessPathApproxNil; + + PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } + + ApNil getApNil(NodeEx node) { + PrevStage::revFlow(node, _) and result = TNil(node.getDataFlowType()) + } + + bindingset[tc, tail] + Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) } + + pragma[noinline] + Content getHeadContent(Ap ap) { result = ap.getHead().getContent() } + + class ApOption = AccessPathApproxOption; + + ApOption apNone() { result = TAccessPathApproxNone() } + + ApOption apSome(Ap ap) { result = TAccessPathApproxSome(ap) } + + import Level1CallContext + import LocalCallContext + + predicate localStep( + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, + ApNil ap, Configuration config, LocalCc lcc + ) { + localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) + } + + pragma[nomagic] + predicate flowOutOfCall( + DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config + ) { + exists(FlowState state | + flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + pragma[nomagic] + predicate flowIntoCall( + DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow, + Configuration config + ) { + exists(FlowState state | + flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and + PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and + PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, + pragma[only_bind_into](config)) + ) + } + + bindingset[node, state, ap, config] + predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { any() } + + // Type checking is not necessary here as it has already been done in stage 3. + bindingset[ap, contentType] + predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } +} + +private module Stage4 = MkStage::Stage; + +bindingset[conf, result] +private Configuration unbindConf(Configuration conf) { + exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c)) +} + +pragma[nomagic] +private predicate nodeMayUseSummary0( + NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(AccessPathApprox apa0 | + Stage4::parameterMayFlowThrough(_, c, _, _) and + Stage4::revFlow(n, state, true, _, apa0, config) and + Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and + n.getEnclosingCallable() = c + ) +} + +pragma[nomagic] +private predicate nodeMayUseSummary( + NodeEx n, FlowState state, AccessPathApprox apa, Configuration config +) { + exists(DataFlowCallable c | + Stage4::parameterMayFlowThrough(_, c, apa, config) and + nodeMayUseSummary0(n, c, state, apa, config) + ) +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { + exists(Configuration config | + Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and + Stage4::revFlow(p, state, _, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParamNodeEx p; + private FlowState s; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, s, ap) } + + ParameterPosition getParameterPos() { p.isParameterOf(_, result) } + + ParamNodeEx getParamNode() { result = p } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** + * Gets the number of length 2 access path approximations that correspond to `apa`. + */ +private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) { + exists(TypedContent tc, int len | + tc = apa.getHead() and + len = apa.len() and + result = + strictcount(AccessPathFront apf | + Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), + config) + ) + ) +} + +private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { + result = + strictcount(NodeEx n, FlowState state | + Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) + ) +} + +/** + * Holds if a length 2 access path approximation matching `apa` is expected + * to be expensive. + */ +private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configuration config) { + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = count1to2unfold(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + apLimit < aps and + tupleLimit < (aps - 1) * nodes + ) +} + +private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { + exists(TypedContent head | + apa.pop(head) = result and + Stage4::consCand(head, result, config) + ) +} + +/** + * Holds with `unfold = false` if a precise head-tail representation of `apa` is + * expected to be expensive. Holds with `unfold = true` otherwise. + */ +private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) { + if apa.getHead().forceHighPrecision() + then unfold = true + else + exists(int aps, int nodes, int apLimit, int tupleLimit | + aps = countPotentialAps(apa, config) and + nodes = countNodesUsingAccessPath(apa, config) and + accessPathCostLimits(apLimit, tupleLimit) and + if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true + ) +} + +/** + * Gets the number of `AccessPath`s that correspond to `apa`. + */ +private int countAps(AccessPathApprox apa, Configuration config) { + evalUnfold(apa, false, config) and + result = 1 and + (not apa instanceof AccessPathApproxCons1 or expensiveLen1to2unfolding(apa, config)) + or + evalUnfold(apa, false, config) and + result = count1to2unfold(apa, config) and + not expensiveLen1to2unfolding(apa, config) + or + evalUnfold(apa, true, config) and + result = countPotentialAps(apa, config) +} + +/** + * Gets the number of `AccessPath`s that would correspond to `apa` assuming + * that it is expanded to a precise head-tail representation. + */ +language[monotonicAggregates] +private int countPotentialAps(AccessPathApprox apa, Configuration config) { + apa instanceof AccessPathApproxNil and result = 1 + or + result = strictsum(AccessPathApprox tail | tail = getATail(apa, config) | countAps(tail, config)) +} + +private newtype TAccessPath = + TAccessPathNil(DataFlowType t) or + TAccessPathCons(TypedContent head, AccessPath tail) { + exists(AccessPathApproxCons apa | + not evalUnfold(apa, false, _) and + head = apa.getHead() and + tail.getApprox() = getATail(apa, _) + ) + } or + TAccessPathCons2(TypedContent head1, TypedContent head2, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + not expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head1 = apa.getHead() and + head2 = getATail(apa, _).getHead() + ) + } or + TAccessPathCons1(TypedContent head, int len) { + exists(AccessPathApproxCons apa | + evalUnfold(apa, false, _) and + expensiveLen1to2unfolding(apa, _) and + apa.len() = len and + head = apa.getHead() + ) + } + +private newtype TPathNode = + TPathNodeMid( + NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config + ) { + // A PathNode is introduced by a source ... + Stage4::revFlow(node, state, config) and + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, state, cc, sc, ap) and + pragma[only_bind_into](config) = mid.getConfiguration() and + Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) + ) + } or + TPathNodeSink(NodeEx node, FlowState state, Configuration config) { + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + state = sink.getState() and + config = sink.getConfiguration() + ) + } + +/** + * A list of `TypedContent`s followed by a `DataFlowType`. If data flows from a + * source to a given node with a given `AccessPath`, this indicates the sequence + * of dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +private class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + abstract TypedContent getHead(); + + /** Gets the tail of this access path, if any. */ + abstract AccessPath getTail(); + + /** Gets the front of this access path. */ + abstract AccessPathFront getFront(); + + /** Gets the approximation of this access path. */ + abstract AccessPathApprox getApprox(); + + /** Gets the length of this access path. */ + abstract int length(); + + /** Gets a textual representation of this access path. */ + abstract string toString(); + + /** Gets the access path obtained by popping `tc` from this access path, if any. */ + final AccessPath pop(TypedContent tc) { + result = this.getTail() and + tc = this.getHead() + } + + /** Gets the access path obtained by pushing `tc` onto this access path. */ + final AccessPath push(TypedContent tc) { this = result.pop(tc) } +} + +private class AccessPathNil extends AccessPath, TAccessPathNil { + private DataFlowType t; + + AccessPathNil() { this = TAccessPathNil(t) } + + DataFlowType getType() { result = t } + + override TypedContent getHead() { none() } + + override AccessPath getTail() { none() } + + override AccessPathFrontNil getFront() { result = TFrontNil(t) } + + override AccessPathApproxNil getApprox() { result = TNil(t) } + + override int length() { result = 0 } + + override string toString() { result = concat(": " + ppReprType(t)) } +} + +private class AccessPathCons extends AccessPath, TAccessPathCons { + private TypedContent head; + private AccessPath tail; + + AccessPathCons() { this = TAccessPathCons(head, tail) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { result = tail } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { + result = TConsNil(head, tail.(AccessPathNil).getType()) + or + result = TConsCons(head, tail.getHead(), this.length()) + or + result = TCons1(head, this.length()) + } + + override int length() { result = 1 + tail.length() } + + private string toStringImpl(boolean needsSuffix) { + exists(DataFlowType t | + tail = TAccessPathNil(t) and + needsSuffix = false and + result = head.toString() + "]" + concat(" : " + ppReprType(t)) + ) + or + result = head + ", " + tail.(AccessPathCons).toStringImpl(needsSuffix) + or + exists(TypedContent tc2, TypedContent tc3, int len | tail = TAccessPathCons2(tc2, tc3, len) | + result = head + ", " + tc2 + ", " + tc3 + ", ... (" and len > 2 and needsSuffix = true + or + result = head + ", " + tc2 + ", " + tc3 + "]" and len = 2 and needsSuffix = false + ) + or + exists(TypedContent tc2, int len | tail = TAccessPathCons1(tc2, len) | + result = head + ", " + tc2 + ", ... (" and len > 1 and needsSuffix = true + or + result = head + ", " + tc2 + "]" and len = 1 and needsSuffix = false + ) + } + + override string toString() { + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" + or + result = "[" + this.toStringImpl(false) + } +} + +private class AccessPathCons2 extends AccessPath, TAccessPathCons2 { + private TypedContent head1; + private TypedContent head2; + private int len; + + AccessPathCons2() { this = TAccessPathCons2(head1, head2, len) } + + override TypedContent getHead() { result = head1 } + + override AccessPath getTail() { + Stage4::consCand(head1, result.getApprox(), _) and + result.getHead() = head2 and + result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + + override AccessPathApproxCons getApprox() { + result = TConsCons(head1, head2, len) or + result = TCons1(head1, len) + } + + override int length() { result = len } + + override string toString() { + if len = 2 + then result = "[" + head1.toString() + ", " + head2.toString() + "]" + else + result = "[" + head1.toString() + ", " + head2.toString() + ", ... (" + len.toString() + ")]" + } +} + +private class AccessPathCons1 extends AccessPath, TAccessPathCons1 { + private TypedContent head; + private int len; + + AccessPathCons1() { this = TAccessPathCons1(head, len) } + + override TypedContent getHead() { result = head } + + override AccessPath getTail() { + Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 + } + + override AccessPathFrontHead getFront() { result = TFrontHead(head) } + + override AccessPathApproxCons getApprox() { result = TCons1(head, len) } + + override int length() { result = len } + + override string toString() { + if len = 1 + then result = "[" + head.toString() + "]" + else result = "[" + head.toString() + ", ... (" + len.toString() + ")]" + } +} + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result } + + /** Gets the `FlowState` of this node. */ + FlowState getState() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getANonHiddenSuccessor() and + reach(this) and + reach(result) + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNodeImpl getASuccessorImpl(); + + private PathNodeImpl getASuccessorIfHidden() { + this.isHidden() and + result = this.getASuccessorImpl() + } + + final PathNodeImpl getANonHiddenSuccessor() { + result = this.getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + abstract NodeEx getNodeEx(); + + predicate isHidden() { + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) + } + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } + + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate directReach(PathNodeImpl n) { + n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor()) +} + +/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ +private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } + +/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNodeImpl n1, PathNode n2) { + n1.getANonHiddenSuccessor() = n2 and directReach(n2) +} + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { + Subpaths::subpaths(arg, par, ret, out) and + reach(arg) and + reach(par) and + reach(ret) and + reach(out) + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + NodeEx node; + FlowState state; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, ap, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbindConf(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = this.getSuccMid() + or + // a final step to a sink + result = this.getSuccMid().projectToSink() + } + + override predicate isSource() { + sourceNode(node, state, config) and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and + sc instanceof SummaryCtxNone and + ap = TAccessPathNil(node.getDataFlowType()) + } + + predicate isAtSink() { + sinkNode(node, state, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getState() = state and + result.getConfiguration() = unbindConf(config) + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + NodeEx node; + FlowState state; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, state, config) } + + override NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + override Configuration getConfiguration() { result = config } + + override PathNodeImpl getASuccessorImpl() { none() } + + override predicate isSource() { sourceNode(node, state, config) } +} + +private predicate pathNode( + PathNodeMid mid, NodeEx midnode, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, + Configuration conf, LocalCallContext localCC +) { + midnode = mid.getNodeEx() and + state = mid.getState() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = + getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)), + midnode.getEnclosingCallable()) and + ap = mid.getAp() +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +pragma[nomagic] +private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap +) { + exists(NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC | + pathNode(mid, midnode, state0, cc, sc, ap, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, true, _, conf, localCC) + ) + or + exists( + AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC + | + pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and + localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNodeEx(), node, mid.getConfiguration()) and + state = mid.getState() and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TAccessPathNil(node.getDataFlowType()) + or + exists(TypedContent tc | pathStoreStep(mid, node, state, ap.pop(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + exists(TypedContent tc | pathReadStep(mid, node, state, ap.push(tc), tc, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, state, _, cc, sc, _, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, state, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, state, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate pathReadStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + tc = ap0.getHead() and + Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc +) { + ap0 = mid.getAp() and + Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and + state = mid.getState() and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, FlowState state, CallContext innercc, AccessPathApprox apa, + Configuration config +) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + apa = mid.getAp().getApprox() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPathApprox apa, Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, state, innercc, apa, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private NodeEx getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config +) { + result.asNode() = kind.getAnOutNode(call) and + Stage4::revFlow(result, _, apa, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, FlowState state, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config | + pathOutOfCallable1(mid, call, kind, state, cc, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, ParameterPosition ppos, FlowState state, CallContext cc, DataFlowCall call, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(ArgNodeEx arg, ArgumentPosition apos | + pathNode(mid, arg, state, cc, _, ap, config, _) and + arg.asNode().(ArgNode).argumentOf(call, apos) and + apa = ap.getApprox() and + parameterMatch(ppos, apos) + ) +} + +pragma[nomagic] +private predicate parameterCand( + DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config +) { + exists(ParamNodeEx p | + Stage4::revFlow(p, _, apa, config) and + p.isParameterOf(callable, pos) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, AccessPath ap, Configuration config +) { + exists(AccessPathApprox apa | + pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, ap, + pragma[only_bind_into](apa), pragma[only_bind_into](config)) and + callable = resolveCall(call, outercc) and + parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) + ) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +pragma[nomagic] +private predicate pathIntoCallable( + PathNodeMid mid, ParamNodeEx p, FlowState state, CallContext outercc, CallContextCall innercc, + SummaryCtx sc, DataFlowCall call, Configuration config +) { + exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + ( + sc = TSummaryCtxSome(p, state, ap) + or + not exists(TSummaryCtxSome(p, state, ap)) and + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, + AccessPathApprox apa, Configuration config +) { + exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | + pathNode(mid, ret, state, cc, sc, ap, config, _) and + kind = ret.getKind() and + apa = ap.getApprox() and + pos = sc.getParameterPos() and + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc, + AccessPath ap, AccessPathApprox apa, Configuration config +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, state, innercc, sc, ap, apa, config) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable( + PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, AccessPath ap +) { + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, state, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) + ) +} + +private module Subpaths { + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths01( + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + exists(Configuration config | + pathThroughCallable(arg, out, pragma[only_bind_into](sout), _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, _, innercc, sc, _, config) and + paramFlowsThrough(kind, pragma[only_bind_into](sout), innercc, sc, + pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by + * `kind`, `sc`, `sout`, `apout`, and `innercc`. + */ + pragma[nomagic] + private predicate subpaths02( + PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + NodeEx out, FlowState sout, AccessPath apout + ) { + subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and + out.asNode() = kind.getAnOutNode(_) + } + + pragma[nomagic] + private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple. + */ + pragma[nomagic] + private predicate subpaths03( + PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout + ) { + exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | + subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and + pathNode(ret, retnode, sout, innercc, sc, apout, unbindConf(getPathNodeConf(arg)), _) and + kind = retnode.getKind() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, _, n2, _, _, _, _, _) or + store(n1, _, n2, _, _) or + readSet(n1, _, n2, _) + ) + } + + pragma[nomagic] + private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getANonHiddenSuccessor() and + succNode = succ.getNodeEx() + } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { + exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | + pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and + subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and + not ret.isHidden() and + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() + ) + } + + /** + * Holds if `n` can reach a return node in a summarized subpath that can reach a sink. + */ + predicate retReach(PathNodeImpl n) { + exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) + or + exists(PathNodeImpl mid | + retReach(mid) and + n.getANonHiddenSuccessor() = mid and + not subpaths(_, mid, _, _) + ) + } +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.(PathNodeImpl).getNodeEx().asNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNodeEx().asNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private predicate finalStats( + boolean fwd, int nodes, int fields, int conscand, int states, int tuples +) { + fwd = true 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and + tuples = count(PathNode pn) + or + fwd = false 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 + states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and + tuples = count(PathNode pn | reach(pn)) +} + +/** + * INTERNAL: Only for debugging. + * + * Calculates per-stage metrics for data flow. + */ +predicate stageStats( + int n, string stage, int nodes, int fields, int conscand, int states, int tuples, + Configuration config +) { + stage = "1 Fwd" and + n = 10 and + Stage1::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "1 Rev" and + n = 15 and + Stage1::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Fwd" and + n = 20 and + Stage2::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "2 Rev" and + n = 25 and + Stage2::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Fwd" and + n = 30 and + Stage3::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "3 Rev" and + n = 35 and + Stage3::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Fwd" and + n = 40 and + Stage4::stats(true, nodes, fields, conscand, states, tuples, config) + or + stage = "4 Rev" and + n = 45 and + Stage4::stats(false, nodes, fields, conscand, states, tuples, config) + or + stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) + or + stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(NodeEx node1, NodeEx node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + additionalJumpStateStep(node1, _, node2, _, config) + or + // flow into callable + viableParamArgEx(_, node2, node1) + or + // flow out of a callable + viableReturnPosOutEx(_, node1.(RetNodeEx).getReturnPosition(), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) or config.isSource(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private predicate interestingCallableSink(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSink(n) or config.isSink(n, _) | c = getNodeEnclosingCallable(n)) + or + exists(DataFlowCallable mid | + interestingCallableSink(mid, config) and callableStep(c, mid, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { + interestingCallableSrc(c, config) or + interestingCallableSink(c, config) + } or + TCallableSrc() or + TCallableSink() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtSink(TCallableSink sink) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, pragma[only_bind_into](config)) and + ce2 = TCallable(c2, pragma[only_bind_into](config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + (config.isSource(n) or config.isSource(n, _)) and + ce2 = TCallable(getNodeEnclosingCallable(n), config) + ) + or + exists(Node n, Configuration config | + ce2 = TCallableSink() and + (config.isSink(n) or config.isSink(n, _)) and + ce1 = TCallable(getNodeEnclosingCallable(n), config) + ) + } + + private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) { + callableExtStepFwd(ce2, ce1) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSinkExt(TCallableExt c) = + shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private int distSink(DataFlowCallable c, Configuration config) { + result = distSinkExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + TypedContent getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | + if len = 1 + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private newtype TRevPartialAccessPath = + TRevPartialNil() or + TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] } + + /** + * Conceptually a list of `Content`s, but only the first + * element of the list and its length are tracked. + */ + private class RevPartialAccessPath extends TRevPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TRevPartialCons(result, _) } + + int len() { + this = TRevPartialNil() and result = 0 + or + this = TRevPartialCons(_, result) + } + } + + private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil { + override string toString() { result = "" } + } + + private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons { + override string toString() { + exists(Content c, int len | this = TRevPartialCons(c, len) | + if len = 1 + then result = "[" + c.toString() + "]" + else result = "[" + c.toString() + ", ... (" + len.toString() + ")]" + ) + } + } + + private predicate relevantState(FlowState state) { + sourceNode(_, state, _) or + sinkNode(_, state, _) or + additionalLocalStateStep(_, state, _, _, _) or + additionalLocalStateStep(_, _, _, state, _) or + additionalJumpStateStep(_, state, _, _, _) or + additionalJumpStateStep(_, _, _, state, _) + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParamNodeEx p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TSummaryCtx3 = + TSummaryCtx3None() or + TSummaryCtx3Some(PartialAccessPath ap) + + private newtype TRevSummaryCtx1 = + TRevSummaryCtx1None() or + TRevSummaryCtx1Some(ReturnPosition pos) + + private newtype TRevSummaryCtx2 = + TRevSummaryCtx2None() or + TRevSummaryCtx2Some(FlowState s) { relevantState(s) } + + private newtype TRevSummaryCtx3 = + TRevSummaryCtx3None() or + TRevSummaryCtx3Some(RevPartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeFwd( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = TPartialNil(node.getDataFlowType()) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } or + TPartialPathNodeRev( + NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, TRevSummaryCtx3 sc3, + RevPartialAccessPath ap, Configuration config + ) { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() and + exists(config.explorationLimit()) + or + exists(PartialPathNodeRev mid | + revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and + not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() + ) + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and + not fullBarrier(node, config) and + not stateBarrier(node, state, config) and + not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and + if node.asNode() instanceof CastingNode + then compatibleTypes(node.getDataFlowType(), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + 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.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + final Node getNode() { this.getNodeEx().projectToNode() = result } + + FlowState getState() { none() } + + private NodeEx getNodeEx() { + result = this.(PartialPathNodeFwd).getNodeEx() or + result = this.(PartialPathNodeRev).getNodeEx() + } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + /** + * Gets the approximate distance to the nearest sink measured in number + * of interprocedural steps. + */ + int getSinkDistance() { + result = distSink(this.getNodeEx().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | + s = this.(PartialPathNodeFwd).getAp().toString() or + s = this.(PartialPathNodeRev).getAp().toString() + | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">" + } + + /** Holds if this is a source in a forward-flow path. */ + predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() } + + /** Holds if this is a sink in a reverse-flow path. */ + predicate isRevSink() { this.(PartialPathNodeRev).isSink() } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd { + NodeEx node; + FlowState state; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + TSummaryCtx3 sc3; + PartialAccessPath ap; + Configuration config; + + PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, state, cc, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TSummaryCtx3 getSummaryCtx3() { result = sc3 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeFwd getASuccessor() { + partialPathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(), + result.getSummaryCtx1(), result.getSummaryCtx2(), result.getSummaryCtx3(), result.getAp(), + result.getConfiguration()) + } + + predicate isSource() { + sourceNode(node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap instanceof TPartialNil + } + } + + private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev { + NodeEx node; + FlowState state; + TRevSummaryCtx1 sc1; + TRevSummaryCtx2 sc2; + TRevSummaryCtx3 sc3; + RevPartialAccessPath ap; + Configuration config; + + PartialPathNodeRev() { this = TPartialPathNodeRev(node, state, sc1, sc2, sc3, ap, config) } + + NodeEx getNodeEx() { result = node } + + override FlowState getState() { result = state } + + TRevSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TRevSummaryCtx2 getSummaryCtx2() { result = sc2 } + + TRevSummaryCtx3 getSummaryCtx3() { result = sc3 } + + RevPartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodeRev getASuccessor() { + revPartialPathStep(result, this.getNodeEx(), this.getState(), this.getSummaryCtx1(), + this.getSummaryCtx2(), this.getSummaryCtx3(), this.getAp(), this.getConfiguration()) + } + + predicate isSink() { + sinkNode(node, state, config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = TRevPartialNil() + } + } + + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalLocalStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNodeEx(), node, config) and + state = mid.getState() and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(node.getDataFlowType()) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsFwd(ap, tc, ap0, config) + ) + or + partialPathIntoCallable(mid, node, state, _, cc, sc1, sc2, sc3, _, ap, config) + or + partialPathOutOfCallable(mid, node, state, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + sc3 = TSummaryCtx3None() + or + partialPathThroughCallable(mid, node, state, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + bindingset[result, i] + private int unbindInt(int i) { pragma[only_bind_out](i) = pragma[only_bind_out](result) } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node, + PartialAccessPath ap2 + ) { + exists(NodeEx midNode, DataFlowType contentType | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType, mid.getConfiguration()) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeFwd mid | + partialPathStoreStep(mid, ap1, tc, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc, + Configuration config + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and + ap.getHead() = tc and + pragma[only_bind_into](config) = mid.getConfiguration() and + cc = mid.getCallContext() + ) + } + + private predicate partialPathOutOfCallable0( + PartialPathNodeFwd mid, ReturnPosition pos, FlowState state, CallContext innercc, + PartialAccessPath ap, Configuration config + ) { + pos = mid.getNodeEx().(RetNodeEx).getReturnPosition() and + state = mid.getState() and + innercc = mid.getCallContext() and + innercc instanceof CallContextNoCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, state, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, state, cc, ap, config) + | + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodeFwd mid, ParameterPosition ppos, FlowState state, CallContext cc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ArgNode arg, ArgumentPosition apos | + arg = mid.getNodeEx().asNode() and + state = mid.getState() and + cc = mid.getCallContext() and + arg.argumentOf(call, apos) and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, + CallContext outercc, DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, pos, state, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodeFwd mid, ParamNodeEx p, FlowState state, CallContext outercc, + CallContextCall innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + exists(ParameterPosition pos, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, pos, state, outercc, call, ap, config) and + p.isParameterOf(callable, pos) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(state) and + sc3 = TSummaryCtx3Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, FlowState state, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeFwd mid, RetNodeEx ret | + mid.getNodeEx() = ret and + kind = ret.getKind() and + state = mid.getState() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, FlowState state, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3 | + partialPathIntoCallable(mid, _, _, cc, innercc, sc1, sc2, sc3, call, _, config) and + paramFlowsThroughInPartialPath(kind, state, innercc, sc1, sc2, sc3, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodeFwd mid, NodeEx out, FlowState state, CallContext cc, PartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, state, cc, ap, config) and + out.asNode() = kind.getAnOutNode(call) + ) + } + + pragma[nomagic] + private predicate revPartialPathStep( + PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, + TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config + ) { + localFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalLocalStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + jumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(node, mid.getNodeEx(), config) and + state = mid.getState() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + additionalJumpStateStep(node, state, mid.getNodeEx(), mid.getState(), config) and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + mid.getAp() instanceof RevPartialAccessPathNil and + ap = TRevPartialNil() and + config = mid.getConfiguration() + or + revPartialPathReadStep(mid, _, _, node, ap) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + config = mid.getConfiguration() + or + exists(RevPartialAccessPath ap0, Content c | + revPartialPathStoreStep(mid, ap0, c, node, config) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + apConsRev(ap, c, ap0, config) + ) + or + exists(ParamNodeEx p | + mid.getNodeEx() = p and + viableParamArgEx(_, p, node) and + state = mid.getState() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + sc1 = TRevSummaryCtx1None() and + sc2 = TRevSummaryCtx2None() and + sc3 = TRevSummaryCtx3None() and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + or + exists(ReturnPosition pos | + revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap, config) and + pos = getReturnPosition(node.asNode()) + ) + or + revPartialPathThroughCallable(mid, node, state, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() + } + + pragma[inline] + private predicate revPartialPathReadStep( + PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, NodeEx node, + RevPartialAccessPath ap2 + ) { + exists(NodeEx midNode | + midNode = mid.getNodeEx() and + ap1 = mid.getAp() and + read(node, c, midNode, mid.getConfiguration()) and + ap2.getHead() = c and + ap2.len() = unbindInt(ap1.len() + 1) + ) + } + + pragma[nomagic] + private predicate apConsRev( + RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodeRev mid | + revPartialPathReadStep(mid, ap1, c, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathStoreStep( + PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config + ) { + exists(NodeEx midNode, TypedContent tc | + midNode = mid.getNodeEx() and + ap = mid.getAp() and + store(node, tc, midNode, _, config) and + ap.getHead() = c and + config = mid.getConfiguration() and + tc.getContent() = c + ) + } + + pragma[nomagic] + private predicate revPartialPathIntoReturn( + PartialPathNodeRev mid, ReturnPosition pos, FlowState state, TRevSummaryCtx1Some sc1, + TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3, DataFlowCall call, RevPartialAccessPath ap, + Configuration config + ) { + exists(NodeEx out | + mid.getNodeEx() = out and + mid.getState() = state and + viableReturnPosOutEx(call, pos, out) and + sc1 = TRevSummaryCtx1Some(pos) and + sc2 = TRevSummaryCtx2Some(state) and + sc3 = TRevSummaryCtx3Some(ap) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate revPartialPathFlowsThrough( + ArgumentPosition apos, FlowState state, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, + TRevSummaryCtx3Some sc3, RevPartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos | + mid.getNodeEx() = p and + mid.getState() = state and + p.getPosition() = ppos and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + sc3 = mid.getSummaryCtx3() and + ap = mid.getAp() and + config = mid.getConfiguration() and + parameterMatch(ppos, apos) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable0( + DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, FlowState state, + RevPartialAccessPath ap, Configuration config + ) { + exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, TRevSummaryCtx3Some sc3 | + revPartialPathIntoReturn(mid, _, _, sc1, sc2, sc3, call, _, config) and + revPartialPathFlowsThrough(pos, state, sc1, sc2, sc3, ap, config) + ) + } + + pragma[nomagic] + private predicate revPartialPathThroughCallable( + PartialPathNodeRev mid, ArgNodeEx node, FlowState state, RevPartialAccessPath ap, + Configuration config + ) { + exists(DataFlowCall call, ArgumentPosition pos | + revPartialPathThroughCallable0(call, mid, pos, state, ap, config) and + node.asNode().(ArgNode).argumentOf(call, pos) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + source.isFwdSource() and + node = source.getASuccessor+() +} + +private predicate revPartialFlow( + PartialPathNode node, PartialPathNode sink, Configuration configuration +) { + sink.getConfiguration() = configuration and + sink.isRevSink() and + node.getASuccessor+() = sink +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll new file mode 100644 index 00000000000..95b34f15dad --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -0,0 +1,1374 @@ +private import DataFlowImplSpecific::Private +private import DataFlowImplSpecific::Public +import Cached + +module DataFlowImplCommonPublic { + /** A state value to track during data flow. */ + class FlowState = string; + + /** + * The default state, which is used when the state is unspecified for a source + * or a sink. + */ + class FlowStateEmpty extends FlowState { + FlowStateEmpty() { this = "" } + } + + private newtype TFlowFeature = + TFeatureHasSourceCallContext() or + TFeatureHasSinkCallContext() or + TFeatureEqualSourceSinkCallContext() + + /** A flow configuration feature for use in `Configuration::getAFeature()`. */ + class FlowFeature extends TFlowFeature { + string toString() { none() } + } + + /** + * A flow configuration feature that implies that sources have some existing + * call context. + */ + class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext { + override string toString() { result = "FeatureHasSourceCallContext" } + } + + /** + * A flow configuration feature that implies that sinks have some existing + * call context. + */ + class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext { + override string toString() { result = "FeatureHasSinkCallContext" } + } + + /** + * A flow configuration feature that implies that source-sink pairs have some + * shared existing call context. + */ + class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext { + override string toString() { result = "FeatureEqualSourceSinkCallContext" } + } +} + +/** + * The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion. + * + * `apLimit` bounds the acceptable fan-out, and `tupleLimit` bounds the + * estimated per-`AccessPathFront` tuple cost. Access paths exceeding both of + * these limits are represented with lower precision during pruning. + */ +predicate accessPathApproxCostLimits(int apLimit, int tupleLimit) { + apLimit = 10 and + tupleLimit = 10000 +} + +/** + * The cost limits for the `AccessPathApprox` to `AccessPath` expansion. + * + * `apLimit` bounds the acceptable fan-out, and `tupleLimit` bounds the + * estimated per-`AccessPathApprox` tuple cost. Access paths exceeding both of + * these limits are represented with lower precision. + */ +predicate accessPathCostLimits(int apLimit, int tupleLimit) { + apLimit = 5 and + tupleLimit = 1000 +} + +/** + * Holds if `arg` is an argument of `call` with an argument position that matches + * parameter position `ppos`. + */ +pragma[noinline] +predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) { + exists(ArgumentPosition apos | + arg.argumentOf(call, apos) and + parameterMatch(ppos, apos) + ) +} + +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lambda + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + pragma[noinline] + private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) { + p.isParameterOf(viableCallable(call), ppos) + } + + pragma[noinline] + private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) { + p.isParameterOf(viableCallableLambda(call, _), ppos) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) { + exists(ParameterPosition ppos | + viableParamNonLambda(call, ppos, p) and + argumentPositionMatch(call, arg, ppos) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) { + exists(ParameterPosition ppos | + viableParamLambda(call, ppos, p) and + argumentPositionMatch(call, arg, ppos) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeDataFlowType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeDataFlowType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeDataFlowType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and + toReturn = false and + toJump = true + | + jumpStepCached(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeDataFlowType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + +cached +private module Cached { + /** + * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby + * collapsing the two stages. + */ + cached + predicate forceCachingInSameStage() { any() } + + cached + predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) } + + cached + predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) { + c = call.getEnclosingCallable() + } + + cached + predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) } + + cached + predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) } + + cached + predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + + cached + predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } + + cached + predicate outNodeExt(Node n) { + n instanceof OutNode + or + n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode + } + + cached + predicate hiddenNode(Node n) { nodeIsHidden(n) } + + cached + OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) { + result = getAnOutNode(call, k.(ValueReturnKind).getKind()) + or + exists(ArgNode arg | + result.(PostUpdateNode).getPreUpdateNode() = arg and + arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition()) + ) + } + + cached + predicate returnNodeExt(Node n, ReturnKindExt k) { + k = TValueReturn(n.(ReturnNode).getKind()) + or + exists(ParamNode p, ParameterPosition pos | + parameterValueFlowsToPreUpdate(p, n) and + p.isParameterOf(_, pos) and + k = TParamUpdate(pos) + ) + } + + cached + predicate castNode(Node n) { n instanceof CastNode } + + cached + predicate castingNode(Node n) { + castNode(n) or + n instanceof ParamNode or + n instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readSet(_, _, n) + } + + cached + predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) { + isParameterNode(p, c, pos) + } + + cached + predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) { + isArgumentNode(n, call, pos) + } + + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + + /** + * Holds if `p` is the parameter of a viable dispatch target of `call`, + * and `p` has position `ppos`. + */ + pragma[nomagic] + private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) { + p.isParameterOf(viableCallableExt(call), ppos) + } + + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) { + exists(ParameterPosition ppos | + viableParam(call, ppos, p) and + argumentPositionMatch(call, arg, ppos) and + compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) + ) + } + + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallableExt(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ + cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ + private module FlowThrough { + /** + * The first flow-through approximation: + * + * - Input access paths are abstracted with a Boolean parameter + * that indicates (non-)emptiness. + */ + private module Cand { + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps. + * + * `read` indicates whether it is contents of `p` that can flow to `node`. + */ + pragma[nomagic] + private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) { + p = node and + read = false + or + // local flow + exists(Node mid | + parameterValueFlowCand(p, mid, read) and + simpleLocalFlowStep(mid, node) + ) + or + // read + exists(Node mid | + parameterValueFlowCand(p, mid, false) and + readSet(mid, _, node) and + read = true + ) + or + // flow through: no prior read + exists(ArgNode arg | + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) + ) + or + // flow through: no read inside method + exists(ArgNode arg | + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) + ) + } + + pragma[nomagic] + private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) + } + + pragma[nomagic] + predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) { + parameterValueFlowCand(p, n.getPreUpdateNode(), false) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + * + * `read` indicates whether it is contents of `p` that can flow to the return + * node. + */ + predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) { + exists(ReturnNode ret | + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() + ) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read + ) { + exists(ParamNode param | viableParamArg(call, param, arg) | + parameterValueFlowReturnCand(param, kind, read) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + * + * `read` indicates whether it is contents of `arg` that can flow to `out`. + */ + predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + ) + } + + predicate cand(ParamNode p, Node n) { + parameterValueFlowCand(p, n, _) and + ( + parameterValueFlowReturnCand(p, _, _) + or + parameterValueFlowsToPreUpdateCand(p, _) + ) + } + } + + /** + * The final flow-through calculation: + * + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. + * - Types are checked using the `compatibleTypes()` relation. + */ + private module Final { + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. + * + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. + */ + predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and + if node instanceof CastingNode + then + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node)) + or + // getter + compatibleTypes(read.getContentType(), getNodeDataFlowType(node)) + else any() + } + + pragma[nomagic] + private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) { + p = node and + Cand::cand(p, _) and + read = TReadStepTypesNone() + or + // local flow + exists(Node mid | + parameterValueFlow(p, mid, read) and + simpleLocalFlowStep(mid, node) + ) + or + // read + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getNodeDataFlowType(p), read.getContainerType()) + ) + or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read + ) { + // flow through: no prior read + exists(ArgNode arg | + parameterValueFlowArg(p, arg, mustBeNone) and + argumentValueFlowsThrough(arg, read, node) + ) + or + // flow through: no read inside method + exists(ArgNode arg | + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, mustBeNone, node) + ) + } + + pragma[nomagic] + private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) { + parameterValueFlow(p, arg, read) and + Cand::argumentValueFlowsThroughCand(arg, _, _) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read + ) { + exists(ParamNode param | viableParamArg(call, param, arg) | + parameterValueFlowReturn(param, kind, read) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. + * + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. + */ + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + | + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out)) + or + // getter + compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeDataFlowType(out)) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + * + * This predicate is exposed for testing only. + */ + predicate getterStep(ArgNode arg, ContentSet c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps and possibly a single read + * step. + * + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. + */ + private predicate parameterValueFlowReturn( + ParamNode p, ReturnKind kind, ReadStepTypesOption read + ) { + exists(ReturnNode ret | + parameterValueFlow(p, ret, read) and + kind = ret.getKind() + ) + } + } + + import Final + } + + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callEnclosingCallable(call, callable) and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * 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. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + cached + predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContextExt(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContextExt(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + cached + predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) } + + cached + predicate storeSet( + Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + contentType = getNodeDataFlowType(node1) and + containerType = getNodeDataFlowType(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readSet(n2, c, n1) and + contentType = getNodeDataFlowType(n1) and + containerType = getNodeDataFlowType(n2) + ) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + exists(ContentSet cs | + c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType) + ) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f`. + * + * This includes reverse steps through reads when the result of the read has + * been stored into, in order to handle cases like `x.f1.f2 = y`. + */ + cached + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) + } + + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + private predicate reverseStepThroughInputOutputAlias( + PostUpdateNode fromNode, PostUpdateNode toNode + ) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() + | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgNode), fromPre) + ) + or + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + + cached + predicate simpleLocalFlowStepExt(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + } + + /** + * Holds if the call context `call` improves virtual dispatch in `callable`. + */ + cached + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { + reducedViableImplInCallContext(_, callable, call) + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { + exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) + } + + cached + predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call) { recordDataFlowCallSite(call, _) } or + TSomeCall() or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) { + exists(ReturnNodeExt ret | + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + cached + newtype TLocalFlowCallContext = + TAnyLocalCall() or + TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) } + + cached + newtype TReturnKindExt = + TValueReturn(ReturnKind kind) or + TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(TypedContent tc) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) +} + +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + +/** + * A `Node` at which a cast can occur such that the type should be checked. + */ +class CastingNode extends Node { + CastingNode() { castingNode(this) } +} + +private predicate readStepWithTypes( + Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content +) { + readSet(n1, c, n2) and + container = getNodeDataFlowType(n1) and + content = getNodeDataFlowType(n2) +} + +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) + } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + ContentSet getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } +} + +/** + * A call context to restrict the targets of virtual dispatch, prune local flow, + * and match the call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call)` : Flow entered through the + * given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable + * or helps prune unreachable nodes in the current callable. + * - `TSomeCall()` : Flow entered through a parameter. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ +abstract class CallContext extends TCallContext { + abstract string toString(); + + /** Holds if this call context is relevant for `callable`. */ + abstract predicate relevantFor(DataFlowCallable callable); +} + +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { + override string toString() { result = "CcAny" } + + override predicate relevantFor(DataFlowCallable callable) { any() } +} + +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} + +class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call | this = TSpecificCall(call) | result = "CcCall(" + call + ")") + } + + override predicate relevantFor(DataFlowCallable callable) { + recordDataFlowCallSite(this.getCall(), callable) + } + + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + + DataFlowCall getCall() { this = TSpecificCall(result) } +} + +class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + + override predicate relevantFor(DataFlowCallable callable) { + exists(ParamNode p | getNodeEnclosingCallable(p) = callable) + } + + override predicate matchesCall(DataFlowCall call) { any() } +} + +class CallContextReturn extends CallContextNoCall, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + + override predicate relevantFor(DataFlowCallable callable) { + exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable)) + } +} + +/** + * A call context that is relevant for pruning local flow. + */ +abstract class LocalCallContext extends TLocalFlowCallContext { + abstract string toString(); + + /** Holds if this call context is relevant for `callable`. */ + abstract predicate relevantFor(DataFlowCallable callable); +} + +class LocalCallContextAny extends LocalCallContext, TAnyLocalCall { + override string toString() { result = "LocalCcAny" } + + override predicate relevantFor(DataFlowCallable callable) { any() } +} + +class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall { + LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) } + + DataFlowCall call; + + DataFlowCall getCall() { result = call } + + override string toString() { result = "LocalCcCall(" + call + ")" } + + override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) } +} + +private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { + exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call)) +} + +/** + * Gets the local call context given the call context and the callable that + * the contexts apply to. + */ +LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) { + ctx.relevantFor(callable) and + if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable) + then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall() + else result instanceof LocalCallContextAny +} + +/** + * The value of a parameter at function entry, viewed as a node in a data + * flow graph. + */ +class ParamNode extends Node { + ParamNode() { parameterNode(this, _, _) } + + /** + * Holds if this node is the parameter of callable `c` at the specified + * position. + */ + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) } +} + +/** A data-flow node that represents a call argument. */ +class ArgNode extends Node { + ArgNode() { argumentNode(this, _, _) } + + /** Holds if this argument occurs at the given position in the given call. */ + final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + argumentNode(this, call, pos) + } +} + +/** + * A node from which flow can return to the caller. This is either a regular + * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. + */ +class ReturnNodeExt extends Node { + ReturnNodeExt() { returnNodeExt(this, _) } + + /** Gets the kind of this returned value. */ + ReturnKindExt getKind() { returnNodeExt(this, result) } +} + +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { outNodeExt(this) } +} + +/** + * An extended return kind. A return kind describes how data can be returned + * from a callable. This can either be through a returned value or an updated + * parameter. + */ +abstract class ReturnKindExt extends TReturnKindExt { + /** Gets a textual representation of this return kind. */ + abstract string toString(); + + /** Gets a node corresponding to data flow out of `call`. */ + final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) } +} + +class ValueReturnKind extends ReturnKindExt, TValueReturn { + private ReturnKind kind; + + ValueReturnKind() { this = TValueReturn(kind) } + + ReturnKind getKind() { result = kind } + + override string toString() { result = kind.toString() } +} + +class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { + private ParameterPosition pos; + + ParamUpdateReturnKind() { this = TParamUpdate(pos) } + + ParameterPosition getPosition() { result = pos } + + pragma[nomagic] + ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) } + + override string toString() { result = "param update " + pos } +} + +/** A callable tagged with a relevant return kind. */ +class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKindExt kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKindExt getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } +} + +/** + * Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this + * predicate ensures that joins go from `n` to the result instead of the other + * way around. + */ +pragma[inline] +DataFlowCallable getNodeEnclosingCallable(Node n) { + nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result)) +} + +/** Gets the type of `n` used for type pruning. */ +pragma[inline] +DataFlowType getNodeDataFlowType(Node n) { + nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result)) +} + +pragma[noinline] +private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) { + result = getNodeEnclosingCallable(ret) +} + +pragma[noinline] +private ReturnPosition getReturnPosition0(ReturnNodeExt ret, ReturnKindExt kind) { + result.getCallable() = returnNodeGetEnclosingCallable(ret) and + kind = result.getKind() +} + +pragma[noinline] +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) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + callEnclosingCallable(call0, callable) and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) +} + +/** + * 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) | + if reducedViableImplInCallContext(call, _, ctx) + then result = prunedViableImplInCallContext(call, ctx) + else result = viableCallableExt(call) + ) + or + result = viableCallableExt(call) and cc instanceof CallContextSomeCall + or + result = viableCallableExt(call) and cc instanceof CallContextAny + or + result = viableCallableExt(call) and cc instanceof CallContextReturn +} + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + +/** A `Content` tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } + + /** + * Holds if access paths with this `TypedContent` at their head always should + * be tracked at high precision. This disables adaptive access path precision + * for such access paths. + */ + predicate forceHighPrecision() { forceHighPrecision(c) } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + TypedContent getHead() { this = TFrontHead(result) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + private DataFlowType t; + + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + private TypedContent tc; + + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll new file mode 100644 index 00000000000..d6c1bad2744 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -0,0 +1,212 @@ +/** + * Provides consistency queries for checking invariants in the language-specific + * data-flow classes and predicates. + */ + +private import DataFlowImplSpecific::Private +private import DataFlowImplSpecific::Public +private import tainttracking1.TaintTrackingParameter::Private +private import tainttracking1.TaintTrackingParameter::Public + +module Consistency { + private newtype TConsistencyConfiguration = MkConsistencyConfiguration() + + /** A class for configuring the consistency queries. */ + class ConsistencyConfiguration extends TConsistencyConfiguration { + string toString() { none() } + + /** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */ + predicate uniqueEnclosingCallableExclude(Node n) { none() } + + /** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */ + predicate uniqueNodeLocationExclude(Node n) { none() } + + /** Holds if `n` should be excluded from the consistency test `missingLocation`. */ + predicate missingLocationExclude(Node n) { none() } + + /** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */ + predicate postWithInFlowExclude(Node n) { none() } + + /** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */ + predicate argHasPostUpdateExclude(ArgumentNode n) { none() } + + /** Holds if `n` should be excluded from the consistency test `reverseRead`. */ + predicate reverseReadExclude(Node n) { none() } + } + + private class RelevantNode extends Node { + RelevantNode() { + this instanceof ArgumentNode or + this instanceof ParameterNode or + this instanceof ReturnNode or + this = getAnOutNode(_, _) or + simpleLocalFlowStep(this, _) or + simpleLocalFlowStep(_, this) or + jumpStep(this, _) or + jumpStep(_, this) or + storeStep(this, _, _) or + storeStep(_, _, this) or + readStep(this, _, _) or + readStep(_, _, this) or + defaultAdditionalTaintStep(this, _) or + defaultAdditionalTaintStep(_, this) + } + } + + query predicate uniqueEnclosingCallable(Node n, string msg) { + exists(int c | + n instanceof RelevantNode and + c = count(nodeGetEnclosingCallable(n)) and + c != 1 and + not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and + msg = "Node should have one enclosing callable but has " + c + "." + ) + } + + query predicate uniqueType(Node n, string msg) { + exists(int c | + n instanceof RelevantNode and + c = count(getNodeType(n)) and + c != 1 and + msg = "Node should have one type but has " + c + "." + ) + } + + query predicate uniqueNodeLocation(Node n, string msg) { + exists(int c | + c = + count(string filepath, int startline, int startcolumn, int endline, int endcolumn | + n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + ) and + c != 1 and + not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and + msg = "Node should have one location but has " + c + "." + ) + } + + query predicate missingLocation(string msg) { + exists(int c | + c = + strictcount(Node n | + not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + ) and + not any(ConsistencyConfiguration conf).missingLocationExclude(n) + ) and + msg = "Nodes without location: " + c + ) + } + + query predicate uniqueNodeToString(Node n, string msg) { + exists(int c | + c = count(n.toString()) and + c != 1 and + msg = "Node should have one toString but has " + c + "." + ) + } + + query predicate missingToString(string msg) { + exists(int c | + c = strictcount(Node n | not exists(n.toString())) and + msg = "Nodes without toString: " + c + ) + } + + query predicate parameterCallable(ParameterNode p, string msg) { + exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and + msg = "Callable mismatch for parameter." + } + + query predicate localFlowIsLocal(Node n1, Node n2, string msg) { + simpleLocalFlowStep(n1, n2) and + nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and + msg = "Local flow step does not preserve enclosing callable." + } + + private DataFlowType typeRepr() { result = getNodeType(_) } + + query predicate compatibleTypesReflexive(DataFlowType t, string msg) { + t = typeRepr() and + not compatibleTypes(t, t) and + msg = "Type compatibility predicate is not reflexive." + } + + query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { + isUnreachableInCall(n, call) and + exists(DataFlowCallable c | + c = nodeGetEnclosingCallable(n) and + not viableCallable(call) = c + ) and + msg = "Call context for isUnreachableInCall is inconsistent with call graph." + } + + query predicate localCallNodes(DataFlowCall call, Node n, string msg) { + ( + n = getAnOutNode(call, _) and + msg = "OutNode and call does not share enclosing callable." + or + n.(ArgumentNode).argumentOf(call, _) and + msg = "ArgumentNode and call does not share enclosing callable." + ) and + nodeGetEnclosingCallable(n) != call.getEnclosingCallable() + } + + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + + query predicate postIsNotPre(PostUpdateNode n, string msg) { + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." + } + + query predicate postHasUniquePre(PostUpdateNode n, string msg) { + exists(int c | + c = count(n.getPreUpdateNode()) and + c != 1 and + msg = "PostUpdateNode should have one pre-update node but has " + c + "." + ) + } + + query predicate uniquePostUpdate(Node n, string msg) { + 1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and + msg = "Node has multiple PostUpdateNodes." + } + + query predicate postIsInSameCallable(PostUpdateNode n, string msg) { + nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and + msg = "PostUpdateNode does not share callable with its pre-update node." + } + + private predicate hasPost(Node n) { exists(PostUpdateNode post | post.getPreUpdateNode() = n) } + + query predicate reverseRead(Node n, string msg) { + exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and + not any(ConsistencyConfiguration conf).reverseReadExclude(n) and + msg = "Origin of readStep is missing a PostUpdateNode." + } + + query predicate argHasPostUpdate(ArgumentNode n, string msg) { + not hasPost(n) and + not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and + msg = "ArgumentNode is missing PostUpdateNode." + } + + // This predicate helps the compiler forget that in some languages + // it is impossible for a `PostUpdateNode` to be the target of + // `simpleLocalFlowStep`. + private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() } + + query predicate postWithInFlow(Node n, string msg) { + isPostUpdateNode(n) and + not clearsContent(n, _) and + simpleLocalFlowStep(_, n) and + not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and + msg = "PostUpdateNode should not be the target of local flow." + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplSpecific.qll new file mode 100644 index 00000000000..4ea383b20a1 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplSpecific.qll @@ -0,0 +1,11 @@ +/** + * Provides IR-specific definitions for use in the data flow library. + */ +module Private { + import DataFlowPrivate + import DataFlowDispatch +} + +module Public { + import DataFlowUtil +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll new file mode 100644 index 00000000000..d6b2d455dd2 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -0,0 +1,560 @@ +private import cpp as Cpp +private import DataFlowUtil +private import semmle.code.cpp.ir.IR +private import DataFlowDispatch +private import DataFlowImplConsistency +private import semmle.code.cpp.ir.internal.IRCppLanguage +private import SsaInternals as Ssa + +/** Gets the callable in which this node occurs. */ +DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } + +/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ +predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) { + p.isParameterOf(c, pos) +} + +/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */ +predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) { + arg.argumentOf(c, pos) +} + +/** + * A data flow node that occurs as the argument of a call and is passed as-is + * to the callable. Instance arguments (`this` pointer) and read side effects + * on parameters are also included. + */ +abstract class ArgumentNode extends Node { + /** + * Holds if this argument occurs at the given position in the given call. + * The instance argument is considered to have index `-1`. + */ + abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos); + + /** Gets the call in which this node is an argument. */ + DataFlowCall getCall() { this.argumentOf(result, _) } +} + +/** + * A data flow node that occurs as the argument to a call, or an + * implicit `this` pointer argument. + */ +private class PrimaryArgumentNode extends ArgumentNode, OperandNode { + override ArgumentOperand op; + + PrimaryArgumentNode() { exists(CallInstruction call | op = call.getAnArgumentOperand()) } + + override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + op = call.getArgumentOperand(pos.(DirectPosition).getIndex()) + } + + override string toStringImpl() { result = argumentOperandToString(op) } +} + +private string argumentOperandToString(ArgumentOperand op) { + exists(Expr unconverted | + unconverted = op.getDef().getUnconvertedResultExpression() and + result = unconverted.toString() + ) + or + // Certain instructions don't map to an unconverted result expression. For these cases + // we fall back to a simpler naming scheme. This can happen in IR-generated constructors. + not exists(op.getDef().getUnconvertedResultExpression()) and + ( + result = "Argument " + op.(PositionalArgumentOperand).getIndex() + or + op instanceof ThisArgumentOperand and result = "Argument this" + ) +} + +private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode { + override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) { + this.getCallInstruction() = dfCall and + pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and + pos.(IndirectionPosition).getIndirectionIndex() = super.getIndirectionIndex() + } + + override string toStringImpl() { + result = argumentOperandToString(this.getAddressOperand()) + " indirection" + } +} + +/** A parameter position represented by an integer. */ +class ParameterPosition = Position; + +/** An argument position represented by an integer. */ +class ArgumentPosition = Position; + +class Position extends TPosition { + abstract string toString(); +} + +class DirectPosition extends Position, TDirectPosition { + int index; + + DirectPosition() { this = TDirectPosition(index) } + + override string toString() { if index = -1 then result = "this" else result = index.toString() } + + int getIndex() { result = index } +} + +class IndirectionPosition extends Position, TIndirectionPosition { + int argumentIndex; + int indirectionIndex; + + IndirectionPosition() { this = TIndirectionPosition(argumentIndex, indirectionIndex) } + + override string toString() { + if argumentIndex = -1 + then if indirectionIndex > 0 then result = "this indirection" else result = "this" + else + if indirectionIndex > 0 + then result = argumentIndex.toString() + " indirection" + else result = argumentIndex.toString() + } + + int getArgumentIndex() { result = argumentIndex } + + int getIndirectionIndex() { result = indirectionIndex } +} + +newtype TPosition = + TDirectPosition(int index) { exists(any(CallInstruction c).getArgument(index)) } or + TIndirectionPosition(int argumentIndex, int indirectionIndex) { + hasOperandAndIndex(_, any(CallInstruction call).getArgumentOperand(argumentIndex), + indirectionIndex) + } + +private newtype TReturnKind = + TNormalReturnKind(int index) { + exists(IndirectReturnNode return | + return.getAddressOperand() = any(ReturnValueInstruction r).getReturnAddressOperand() and + index = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value. + ) + } or + TIndirectReturnKind(int argumentIndex, int indirectionIndex) { + exists(IndirectReturnNode return, ReturnIndirectionInstruction returnInd | + returnInd.hasIndex(argumentIndex) and + return.getAddressOperand() = returnInd.getSourceAddressOperand() and + indirectionIndex = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value. + ) + } + +/** + * A return kind. A return kind describes how a value can be returned + * from a callable. For C++, this is simply a function return. + */ +class ReturnKind extends TReturnKind { + /** Gets a textual representation of this return kind. */ + abstract string toString(); +} + +private class NormalReturnKind extends ReturnKind, TNormalReturnKind { + int index; + + NormalReturnKind() { this = TNormalReturnKind(index) } + + override string toString() { result = "indirect return" } +} + +private class IndirectReturnKind extends ReturnKind, TIndirectReturnKind { + int argumentIndex; + int indirectionIndex; + + IndirectReturnKind() { this = TIndirectReturnKind(argumentIndex, indirectionIndex) } + + override string toString() { result = "indirect outparam[" + argumentIndex.toString() + "]" } +} + +/** A data flow node that occurs as the result of a `ReturnStmt`. */ +class ReturnNode extends Node instanceof IndirectReturnNode { + /** Gets the kind of this returned value. */ + abstract ReturnKind getKind(); +} + +/** + * This predicate represents an annoying hack that we have to do. We use the + * `ReturnIndirectionInstruction` to determine which variables need flow back + * out of a function. However, the IR will unconditionally create those for a + * variable passed to a function even though the variable was never updated by + * the function. And if a function has too many `ReturnNode`s the dataflow + * library lowers its precision for that function by disabling field flow. + * + * So we those eliminate `ReturnNode`s that would have otherwise been created + * by this unconditional `ReturnIndirectionInstruction` by requiring that there + * must exist an SSA definition of the IR variable in the function. + */ +private predicate hasNonInitializeParameterDef(IRVariable v) { + exists(Ssa::Def def | + not def.getDefiningInstruction() instanceof InitializeParameterInstruction and + v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable() + ) +} + +class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode { + override ReturnKind getKind() { + exists(int argumentIndex, ReturnIndirectionInstruction returnInd | + returnInd.hasIndex(argumentIndex) and + this.getAddressOperand() = returnInd.getSourceAddressOperand() and + result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex() - 1) and + hasNonInitializeParameterDef(returnInd.getIRVariable()) + ) + or + this.getAddressOperand() = any(ReturnValueInstruction r).getReturnAddressOperand() and + result = TNormalReturnKind(this.getIndirectionIndex() - 1) + } +} + +private Operand fullyConvertedCallStep(Operand op) { + not exists(getANonConversionUse(op)) and + exists(Instruction instr | + conversionFlow(op, instr, _) and + result = getAUse(instr) + ) +} + +/** + * Gets the instruction that uses this operand, if the instruction is not + * ignored for dataflow purposes. + */ +private Instruction getUse(Operand op) { + result = op.getUse() and + not Ssa::ignoreOperand(op) +} + +/** Gets a use of the instruction `instr` that is not ignored for dataflow purposes. */ +Operand getAUse(Instruction instr) { + result = instr.getAUse() and + not Ssa::ignoreOperand(result) +} + +/** + * Gets a use of `operand` that is: + * - not ignored for dataflow purposes, and + * - not a conversion-like instruction. + */ +private Instruction getANonConversionUse(Operand operand) { + result = getUse(operand) and + not conversionFlow(_, result, _) +} + +/** + * Gets the operand that represents the first use of the value of `call` following + * a sequnce of conversion-like instructions. + */ +predicate operandForfullyConvertedCall(Operand operand, CallInstruction call) { + exists(getANonConversionUse(operand)) and + ( + operand = getAUse(call) + or + operand = fullyConvertedCallStep*(getAUse(call)) + ) +} + +/** + * Gets the instruction that represents the first use of the value of `call` following + * a sequnce of conversion-like instructions. + * + * This predicate only holds if there is no suitable operand (i.e., no operand of a non- + * conversion instruction) to use to represent the value of `call` after conversions. + */ +predicate instructionForfullyConvertedCall(Instruction instr, CallInstruction call) { + not operandForfullyConvertedCall(_, call) and + ( + // If there is no use of the call then we pick the call instruction + not exists(getAUse(call)) and + instr = call + or + // Otherwise, flow to the first non-conversion use. + exists(Operand operand | operand = fullyConvertedCallStep*(getAUse(call)) | + instr = getANonConversionUse(operand) + ) + ) +} + +/** Holds if `node` represents the output node for `call`. */ +private predicate simpleOutNode(Node node, CallInstruction call) { + operandForfullyConvertedCall(node.asOperand(), call) + or + instructionForfullyConvertedCall(node.asInstruction(), call) +} + +/** A data flow node that represents the output of a call. */ +class OutNode extends Node { + OutNode() { + // Return values not hidden behind indirections + simpleOutNode(this, _) + or + // Return values hidden behind indirections + this instanceof IndirectReturnOutNode + or + // Modified arguments hidden behind indirections + this instanceof IndirectArgumentOutNode + } + + /** Gets the underlying call. */ + abstract DataFlowCall getCall(); + + abstract ReturnKind getReturnKind(); +} + +private class DirectCallOutNode extends OutNode { + CallInstruction call; + + DirectCallOutNode() { simpleOutNode(this, call) } + + override DataFlowCall getCall() { result = call } + + override ReturnKind getReturnKind() { result = TNormalReturnKind(0) } +} + +private class IndirectCallOutNode extends OutNode, IndirectReturnOutNode { + override DataFlowCall getCall() { result = this.getCallInstruction() } + + override ReturnKind getReturnKind() { result = TNormalReturnKind(this.getIndirectionIndex()) } +} + +private class SideEffectOutNode extends OutNode, IndirectArgumentOutNode { + override DataFlowCall getCall() { result = this.getCallInstruction() } + + override ReturnKind getReturnKind() { + result = TIndirectReturnKind(this.getArgumentIndex(), this.getIndirectionIndex()) + } +} + +/** + * Gets a node that can read the value returned from `call` with return kind + * `kind`. + */ +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { + result.getCall() = call and + result.getReturnKind() = kind +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that loses the + * calling context. For example, this would happen with flow through a + * global or static variable. + */ +predicate jumpStep(Node n1, Node n2) { + exists(Cpp::GlobalOrNamespaceVariable v | + v = + n1.asInstruction() + .(StoreInstruction) + .getResultAddress() + .(VariableAddressInstruction) + .getAstVariable() and + v = n2.asVariable() + or + v = + n2.asInstruction() + .(LoadInstruction) + .getSourceAddress() + .(VariableAddressInstruction) + .getAstVariable() and + v = n1.asVariable() + ) +} + +/** + * Holds if data can flow from `node1` to `node2` via an assignment to `f`. + * Thus, `node2` references an object with a field `f` that contains the + * value of `node1`. + */ +predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) { + exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store | + nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and + node2.getIndirectionIndex() = 0 and + numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(), + numberOfLoads) + | + exists(FieldContent fc | fc = c | + fc.getField() = node2.getUpdatedField() and + fc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads + ) + or + exists(UnionContent uc | uc = c | + uc.getAField() = node2.getUpdatedField() and + uc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads + ) + ) +} + +/** + * Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like + * operations and exactly `n` `LoadInstruction` operations. + */ +private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand operandTo, int ind) { + exists(LoadInstruction load | load.getSourceAddressOperand() = operandFrom | + operandTo = operandFrom and ind = 0 + or + numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1) + ) + or + exists(Operand op, Instruction instr | + instr = op.getDef() and + conversionFlow(operandFrom, instr, _) and + numberOfLoadsFromOperand(op, operandTo, ind) + ) +} + +/** + * Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like + * operations and exactly `n` `LoadInstruction` operations. + */ +private predicate numberOfLoadsFromOperand(Operand operandFrom, Operand operandTo, int n) { + numberOfLoadsFromOperandRec(operandFrom, operandTo, n) + or + not any(LoadInstruction load).getSourceAddressOperand() = operandFrom and + not conversionFlow(operandFrom, _, _) and + operandFrom = operandTo and + n = 0 +} + +// Needed to join on both an operand and an index at the same time. +pragma[noinline] +predicate nodeHasOperand(Node node, Operand operand, int indirectionIndex) { + node.asOperand() = operand and indirectionIndex = 0 + or + hasOperandAndIndex(node, operand, indirectionIndex) +} + +// Needed to join on both an instruction and an index at the same time. +pragma[noinline] +predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex) { + node.asInstruction() = instr and indirectionIndex = 0 + or + hasInstructionAndIndex(node, instr, indirectionIndex) +} + +/** + * Holds if data can flow from `node1` to `node2` via a read of `f`. + * Thus, `node1` references an object with a field `f` whose value ends up in + * `node2`. + */ +predicate readStep(Node node1, Content c, Node node2) { + exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 | + nodeHasOperand(node2, operand, indirectionIndex2) and + nodeHasOperand(node1, fa1.getObjectAddressOperand(), _) and + numberOfLoadsFromOperand(fa1, operand, numberOfLoads) + | + exists(FieldContent fc | fc = c | + fc.getField() = fa1.getField() and + fc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads + ) + or + exists(UnionContent uc | uc = c | + uc.getAField() = fa1.getField() and + uc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads + ) + ) +} + +/** + * Holds if values stored inside content `c` are cleared at node `n`. + */ +predicate clearsContent(Node n, Content c) { + none() // stub implementation +} + +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + +/** Gets the type of `n` used for type pruning. */ +IRType getNodeType(Node n) { + suppressUnusedNode(n) and + result instanceof IRVoidType // stub implementation +} + +/** Gets a string representation of a type returned by `getNodeType`. */ +string ppReprType(IRType t) { none() } // stub implementation + +/** + * Holds if `t1` and `t2` are compatible, that is, whether data can flow from + * a node of type `t1` to a node of type `t2`. + */ +pragma[inline] +predicate compatibleTypes(IRType t1, IRType t2) { + any() // stub implementation +} + +private predicate suppressUnusedNode(Node n) { any() } + +////////////////////////////////////////////////////////////////////////////// +// Java QL library compatibility wrappers +////////////////////////////////////////////////////////////////////////////// +/** A node that performs a type cast. */ +class CastNode extends Node { + CastNode() { none() } // stub implementation +} + +/** + * A function that may contain code or a variable that may contain itself. When + * flow crosses from one _enclosing callable_ to another, the interprocedural + * data-flow library discards call contexts and inserts a node in the big-step + * relation used for human-readable path explanations. + */ +class DataFlowCallable = Cpp::Declaration; + +class DataFlowExpr = Expr; + +class DataFlowType = IRType; + +/** A function call relevant for data flow. */ +class DataFlowCall extends CallInstruction { + Function getEnclosingCallable() { result = this.getEnclosingFunction() } +} + +predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation + +int accessPathLimit() { result = 5 } + +/** + * Holds if access paths with `c` at their head always should be tracked at high + * precision. This disables adaptive access path precision for such access paths. + */ +predicate forceHighPrecision(Content c) { none() } + +/** The unit type. */ +private newtype TUnit = TMkUnit() + +/** The trivial type with a single element. */ +class Unit extends TUnit { + /** Gets a textual representation of this element. */ + string toString() { result = "unit" } +} + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() } + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() } + +/** Extra data-flow steps needed for lambda flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } + +/** + * Holds if flow is allowed to pass from parameter `p` and back to itself as a + * side-effect, resulting in a summary from `p` to itself. + * + * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed + * by default as a heuristic. + */ +predicate allowParameterReturnInSelf(ParameterNode p) { none() } + +private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration { + override predicate argHasPostUpdateExclude(ArgumentNode n) { + // The rules for whether an IR argument gets a post-update node are too + // complex to model here. + any() + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll new file mode 100644 index 00000000000..b3b055bc9a1 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -0,0 +1,1346 @@ +/** + * Provides C++-specific definitions for use in the data flow library. + */ + +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.controlflow.IRGuards +private import semmle.code.cpp.models.interfaces.DataFlow +private import DataFlowPrivate +private import ModelUtil +private import SsaInternals as Ssa + +cached +private module Cached { + /** + * The IR dataflow graph consists of the following nodes: + * - `InstructionNode`, which injects most instructions directly into the dataflow graph. + * - `OperandNode`, which similarly injects most operands directly into the dataflow graph. + * - `VariableNode`, which is used to model flow through global variables. + * - `PostFieldUpdateNode`, which is used to model the state of a field after a value has been stored + * into an address after a number of loads. + * - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library. + * - `IndirectArgumentOutNode`, which represents the value of an argument (and its indirections) after + * it leaves a function call. + * - `IndirectOperand`, which represents the value of `operand` after loading the address a number + * of times. + * - `IndirectInstruction`, which represents the value of `instr` after loading the address a number + * of times. + */ + cached + newtype TIRDataFlowNode = + TInstructionNode(Instruction i) { not Ssa::ignoreInstruction(i) } or + TOperandNode(Operand op) { not Ssa::ignoreOperand(op) } or + TVariableNode(Variable var) or + TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) { + indirectionIndex = + [0 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType()) - + 1] + } or + TSsaPhiNode(Ssa::PhiNode phi) or + TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) { + Ssa::isModifiableByCall(operand) and + indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(operand.getLanguageType()) - 1] + } or + TIndirectOperand(Operand op, int indirectionIndex) { + Ssa::hasIndirectOperand(op, indirectionIndex) + } or + TIndirectInstruction(Instruction instr, int indirectionIndex) { + Ssa::hasIndirectInstruction(instr, indirectionIndex) + } +} + +/** + * An operand that is defined by a `FieldAddressInstruction`. + */ +class FieldAddress extends Operand { + FieldAddressInstruction fai; + + FieldAddress() { fai = this.getDef() } + + /** Gets the field associated with this instruction. */ + Field getField() { result = fai.getField() } + + /** Gets the instruction whose result provides the address of the object containing the field. */ + Instruction getObjectAddress() { result = fai.getObjectAddress() } + + /** Gets the operand that provides the address of the object containing the field. */ + Operand getObjectAddressOperand() { result = fai.getObjectAddressOperand() } +} + +/** + * Holds if `opFrom` is an operand whose value flows to the result of `instrTo`. + * + * `isPointerArith` is `true` if `instrTo` is a `PointerArithmeticInstruction` and `opFrom` + * is the left operand. + */ +predicate conversionFlow(Operand opFrom, Instruction instrTo, boolean isPointerArith) { + isPointerArith = false and + ( + instrTo.(CopyValueInstruction).getSourceValueOperand() = opFrom + or + instrTo.(ConvertInstruction).getUnaryOperand() = opFrom + or + instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom + or + instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom + ) + or + isPointerArith = true and + instrTo.(PointerArithmeticInstruction).getLeftOperand() = opFrom +} + +private import Cached + +/** + * A node in a data flow graph. + * + * A node can be either an expression, a parameter, or an uninitialized local + * variable. Such nodes are created with `DataFlow::exprNode`, + * `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively. + */ +class Node extends TIRDataFlowNode { + /** + * INTERNAL: Do not use. + */ + Declaration getEnclosingCallable() { none() } // overridden in subclasses + + /** Gets the function to which this node belongs, if any. */ + Declaration getFunction() { none() } // overridden in subclasses + + /** Gets the type of this node. */ + IRType getType() { none() } // overridden in subclasses + + /** Gets the instruction corresponding to this node, if any. */ + Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } + + /** Gets the operands corresponding to this node, if any. */ + Operand asOperand() { result = this.(OperandNode).getOperand() } + + /** + * Gets the non-conversion expression corresponding to this node, if any. + * This predicate only has a result on nodes that represent the value of + * evaluating the expression. For data flowing _out of_ an expression, like + * when an argument is passed by reference, use `asDefiningArgument` instead + * of `asExpr`. + * + * If this node strictly (in the sense of `asConvertedExpr`) corresponds to + * a `Conversion`, then the result is the underlying non-`Conversion` base + * expression. + */ + Expr asExpr() { result = this.(ExprNode).getExpr() } + + /** + * Gets the non-conversion expression that's indirectly tracked by this node + * under `index` number of indirections. + */ + Expr asIndirectExpr(int index) { + exists(Operand operand | hasOperandAndIndex(this, operand, index) | + result = operand.getDef().getUnconvertedResultExpression() + ) + } + + /** + * Gets the non-conversion expression that's indirectly tracked by this node + * behind a number of indirections. + */ + Expr asIndirectExpr() { result = this.asIndirectExpr(_) } + + /** + * Gets the expression corresponding to this node, if any. The returned + * expression may be a `Conversion`. + */ + Expr asConvertedExpr() { result = this.(ExprNode).getConvertedExpr() } + + /** + * Gets the expression that's indirectly tracked by this node + * behind `index` number of indirections. + */ + Expr asIndirectConvertedExpr(int index) { + exists(Operand operand | hasOperandAndIndex(this, operand, index) | + result = operand.getDef().getConvertedResultExpression() + ) + } + + /** + * Gets the expression that's indirectly tracked by this node behind a + * number of indirections. + */ + Expr asIndirectConvertedExpr() { result = this.asIndirectConvertedExpr(_) } + + /** + * Gets the argument that defines this `DefinitionByReferenceNode`, if any. + * This predicate should be used instead of `asExpr` when referring to the + * value of a reference argument _after_ the call has returned. For example, + * in `f(&x)`, this predicate will have `&x` as its result for the `Node` + * that represents the new value of `x`. + */ + Expr asDefiningArgument() { result = this.asDefiningArgument(_) } + + /** + * Gets the argument that defines this `DefinitionByReferenceNode`, if any. + * + * Unlike `Node::asDefiningArgument/0`, this predicate gets the node representing + * the value of the `index`'th indirection after leaving a function. For example, + * in: + * ```cpp + * void f(int**); + * ... + * int** x = ...; + * f(x); + * ``` + * The node `n` such that `n.asDefiningArgument(1)` is the argument `x` will + * contain the value of `*x` after `f` has returned, and the node `n` such that + * `n.asDefiningArgument(2)` is the argument `x` will contain the value of `**x` + * after the `f` has returned. + */ + Expr asDefiningArgument(int index) { + // Subtract one because `DefinitionByReferenceNode` is defined to be in + // the range `[0 ... n - 1]` for some `n` instead of `[1 ... n]`. + this.(DefinitionByReferenceNode).getIndirectionIndex() = index - 1 and + result = this.(DefinitionByReferenceNode).getArgument() + } + + /** + * Gets the the argument going into a function for a node that represents + * the indirect value of the argument after `index` loads. For example, in: + * ```cpp + * void f(int**); + * ... + * int** x = ...; + * f(x); + * ``` + * The node `n` such that `n.asIndirectArgument(1)` represents the value of + * `*x` going into `f`, and the node `n` such that `n.asIndirectArgument(2)` + * represents the value of `**x` going into `f`. + */ + Expr asIndirectArgument(int index) { + this.(SideEffectOperandNode).getIndirectionIndex() = index and + result = this.(SideEffectOperandNode).getArgument() + } + + /** + * Gets the the argument going into a function for a node that represents + * the indirect value of the argument after any non-zero number of loads. + */ + Expr asIndirectArgument() { result = this.asIndirectArgument(_) } + + /** Gets the positional parameter corresponding to this node, if any. */ + Parameter asParameter() { result = asParameter(0) } + + /** + * Gets the positional parameter corresponding to the node that represents + * the value of the parameter after `index` number of loads, if any. For + * example, in: + * ```cpp + * void f(int** x) { ... } + * ``` + * - The node `n` such that `n.asParameter(0)` is the parameter `x` represents + * the value of `x`. + * - The node `n` such that `n.asParameter(1)` is the parameter `x` represents + * the value of `*x`. + * The node `n` such that `n.asParameter(2)` is the parameter `x` represents + * the value of `**x`. + */ + Parameter asParameter(int index) { + index = 0 and + result = this.(ExplicitParameterNode).getParameter() + or + this.(IndirectParameterNode).getIndirectionIndex() = index and + result = this.(IndirectParameterNode).getParameter() + } + + /** + * Gets the variable corresponding to this node, if any. This can be used for + * modeling flow in and out of global variables. + */ + Variable asVariable() { result = this.(VariableNode).getVariable() } + + /** + * Gets the expression that is partially defined by this node, if any. + * + * Partial definitions are created for field stores (`x.y = taint();` is a partial + * definition of `x`), and for calls that may change the value of an object (so + * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is + * a partial definition of `&x`). + */ + Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() } + + /** + * Gets an upper bound on the type of this node. + */ + IRType getTypeBound() { result = this.getType() } + + /** Gets the location of this element. */ + cached + final Location getLocation() { result = this.getLocationImpl() } + + /** INTERNAL: Do not use. */ + Location getLocationImpl() { + none() // overridden by subclasses + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets a textual representation of this element. */ + cached + final string toString() { result = this.toStringImpl() } + + /** INTERNAL: Do not use. */ + string toStringImpl() { + none() // overridden by subclasses + } +} + +/** + * An instruction, viewed as a node in a data flow graph. + */ +class InstructionNode extends Node, TInstructionNode { + Instruction instr; + + InstructionNode() { this = TInstructionNode(instr) } + + /** Gets the instruction corresponding to this node. */ + Instruction getInstruction() { result = instr } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Declaration getFunction() { result = instr.getEnclosingFunction() } + + override IRType getType() { result = instr.getResultIRType() } + + final override Location getLocationImpl() { result = instr.getLocation() } + + override string toStringImpl() { + // This predicate is overridden in subclasses. This default implementation + // does not use `Instruction.toString` because that's expensive to compute. + result = this.getInstruction().getOpcode().toString() + } +} + +/** + * An operand, viewed as a node in a data flow graph. + */ +class OperandNode extends Node, TOperandNode { + Operand op; + + OperandNode() { this = TOperandNode(op) } + + /** Gets the operand corresponding to this node. */ + Operand getOperand() { result = op } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Declaration getFunction() { result = op.getUse().getEnclosingFunction() } + + override IRType getType() { result = op.getIRType() } + + final override Location getLocationImpl() { result = op.getLocation() } + + override string toStringImpl() { result = this.getOperand().toString() } +} + +/** + * INTERNAL: do not use. + * + * The node representing the value of a field after it has been updated. + */ +class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode { + int indirectionIndex; + FieldAddress fieldAddress; + + PostFieldUpdateNode() { this = TPostFieldUpdateNode(fieldAddress, indirectionIndex) } + + override Function getFunction() { result = fieldAddress.getUse().getEnclosingFunction() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override IRType getType() { result = fieldAddress.getIRType() } + + FieldAddress getFieldAddress() { result = fieldAddress } + + Field getUpdatedField() { result = fieldAddress.getField() } + + int getIndirectionIndex() { result = indirectionIndex } + + override Node getPreUpdateNode() { + // + 1 because we're storing into an lvalue, and the original node should be the rvalue of + // the same address. + hasOperandAndIndex(result, pragma[only_bind_into](fieldAddress).getObjectAddressOperand(), + indirectionIndex + 1) + } + + override Expr getDefinedExpr() { + result = fieldAddress.getObjectAddress().getUnconvertedResultExpression() + } + + override Location getLocationImpl() { result = fieldAddress.getLocation() } + + override string toStringImpl() { result = this.getPreUpdateNode() + " [post update]" } +} + +/** + * INTERNAL: do not use. + * + * A phi node produced by the shared SSA library, viewed as a node in a data flow graph. + */ +class SsaPhiNode extends Node, TSsaPhiNode { + Ssa::PhiNode phi; + + SsaPhiNode() { this = TSsaPhiNode(phi) } + + /** Gets the phi node associated with this node. */ + Ssa::PhiNode getPhiNode() { result = phi } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() } + + override IRType getType() { result instanceof IRVoidType } + + final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() } + + override string toStringImpl() { result = "Phi" } +} + +/** + * INTERNAL: do not use. + * + * A node representing a value after leaving a function. + */ +class SideEffectOperandNode extends Node, IndirectOperand { + CallInstruction call; + int argumentIndex; + + SideEffectOperandNode() { operand = call.getArgumentOperand(argumentIndex) } + + CallInstruction getCallInstruction() { result = call } + + Operand getAddressOperand() { result = operand } + + int getArgumentIndex() { result = argumentIndex } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = call.getEnclosingFunction() } + + override IRType getType() { result instanceof IRVoidType } + + Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() } +} + +/** + * INTERNAL: do not use. + * + * A node representing an indirection of a parameter. + */ +class IndirectParameterNode extends Node, IndirectInstruction { + InitializeParameterInstruction init; + + IndirectParameterNode() { this.getInstruction() = init } + + int getArgumentIndex() { init.hasIndex(result) } + + /** Gets the parameter whose indirection is initialized. */ + Parameter getParameter() { result = init.getParameter() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = this.getInstruction().getEnclosingFunction() } + + override IRType getType() { result instanceof IRVoidType } + + override string toStringImpl() { + result = this.getParameter().toString() + " indirection" + or + not exists(this.getParameter()) and + result = "this indirection" + } +} + +/** + * INTERNAL: do not use. + * + * A node representing the indirection of a value that is + * about to be returned from a function. + */ +class IndirectReturnNode extends IndirectOperand { + IndirectReturnNode() { + this.getOperand() = any(ReturnIndirectionInstruction ret).getSourceAddressOperand() + or + this.getOperand() = any(ReturnValueInstruction ret).getReturnAddressOperand() + } + + Operand getAddressOperand() { result = operand } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override IRType getType() { result instanceof IRVoidType } +} + +/** + * INTERNAL: do not use. + * + * A node representing the indirection of a value after it + * has been returned from a function. + */ +class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PostUpdateNode { + ArgumentOperand operand; + int indirectionIndex; + + IndirectArgumentOutNode() { this = TIndirectArgumentOutNode(operand, indirectionIndex) } + + int getIndirectionIndex() { result = indirectionIndex } + + int getArgumentIndex() { + exists(CallInstruction call | call.getArgumentOperand(result) = operand) + } + + Operand getAddressOperand() { result = operand } + + CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand } + + Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = this.getCallInstruction().getEnclosingFunction() } + + override IRType getType() { result instanceof IRVoidType } + + override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex + 1) } + + override string toStringImpl() { + // This string should be unique enough to be helpful but common enough to + // avoid storing too many different strings. + result = this.getStaticCallTarget().getName() + " output argument" + or + not exists(this.getStaticCallTarget()) and + result = "output argument" + } + + override Location getLocationImpl() { result = operand.getLocation() } +} + +pragma[nomagic] +predicate indirectReturnOutNodeOperand0(CallInstruction call, Operand operand, int indirectionIndex) { + Ssa::hasIndirectInstruction(call, indirectionIndex) and + operandForfullyConvertedCall(operand, call) +} + +pragma[nomagic] +predicate indirectReturnOutNodeInstruction0( + CallInstruction call, Instruction instr, int indirectionIndex +) { + Ssa::hasIndirectInstruction(call, indirectionIndex) and + instructionForfullyConvertedCall(instr, call) +} + +/** + * INTERNAL: do not use. + * + * A node representing the value of a function call. + */ +class IndirectReturnOutNode extends Node { + CallInstruction call; + int indirectionIndex; + + IndirectReturnOutNode() { + // Annoyingly, we need to pick the fully converted value as the output of the function to + // make flow through in the shared dataflow library work correctly. + exists(Operand operand | + indirectReturnOutNodeOperand0(call, operand, indirectionIndex) and + hasOperandAndIndex(this, operand, indirectionIndex) + ) + or + exists(Instruction instr | + indirectReturnOutNodeInstruction0(call, instr, indirectionIndex) and + hasInstructionAndIndex(this, instr, indirectionIndex) + ) + } + + CallInstruction getCallInstruction() { result = call } + + int getIndirectionIndex() { result = indirectionIndex } +} + +/** + * INTERNAL: Do not use. + * + * A node that represents the indirect value of an operand in the IR + * after `index` number of loads. + */ +class IndirectOperand extends Node, TIndirectOperand { + Operand operand; + int indirectionIndex; + + IndirectOperand() { this = TIndirectOperand(operand, indirectionIndex) } + + /** Gets the underlying instruction. */ + Operand getOperand() { result = operand } + + int getIndirectionIndex() { result = indirectionIndex } + + override Function getFunction() { result = this.getOperand().getDef().getEnclosingFunction() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override IRType getType() { result = this.getOperand().getIRType() } + + final override Location getLocationImpl() { result = this.getOperand().getLocation() } + + override string toStringImpl() { + result = instructionNode(this.getOperand().getDef()).toStringImpl() + " indirection" + } +} + +/** + * INTERNAL: Do not use. + * + * A node that represents the indirect value of an instruction in the IR + * after `index` number of loads. + */ +class IndirectInstruction extends Node, TIndirectInstruction { + Instruction instr; + int indirectionIndex; + + IndirectInstruction() { this = TIndirectInstruction(instr, indirectionIndex) } + + /** Gets the underlying instruction. */ + Instruction getInstruction() { result = instr } + + int getIndirectionIndex() { result = indirectionIndex } + + override Function getFunction() { result = this.getInstruction().getEnclosingFunction() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override IRType getType() { result = this.getInstruction().getResultIRType() } + + final override Location getLocationImpl() { result = this.getInstruction().getLocation() } + + override string toStringImpl() { + result = instructionNode(this.getInstruction()).toStringImpl() + " indirection" + } +} + +private predicate isFullyConvertedArgument(Expr e) { + e = any(Call call).getAnArgument().getFullyConverted() +} + +private predicate isFullyConvertedCall(Expr e) { e = any(Call call).getFullyConverted() } + +/** Holds if `Node::asExpr` should map an some operand node to `e`. */ +private predicate convertedExprMustBeOperand(Expr e) { + isFullyConvertedArgument(e) + or + isFullyConvertedCall(e) +} + +/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */ +predicate exprNodeShouldBeOperand(Node node, Expr e) { + e = node.asOperand().getDef().getConvertedResultExpression() and + convertedExprMustBeOperand(e) +} + +/** + * Holds if `load` is a `LoadInstruction` that is the result of evaluating `e` + * and `node` is an `IndirctOperandNode` that should map `node.asExpr()` to `e`. + * + * We map `e` to `node.asExpr()` when `node` semantically represents the + * same value as `load`. A subsequent flow step will flow `node` to + * the `LoadInstruction`. + */ +private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, LoadInstruction load) { + node.getIndirectionIndex() = 1 and + e = load.getConvertedResultExpression() and + load.getSourceAddressOperand() = node.getOperand() and + not convertedExprMustBeOperand(e) +} + +/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */ +predicate exprNodeShouldBeInstruction(Node node, Expr e) { + e = node.asInstruction().getConvertedResultExpression() and + not exprNodeShouldBeOperand(_, e) and + not exprNodeShouldBeIndirectOperand(_, e, _) +} + +private class ExprNodeBase extends Node { + Expr getConvertedExpr() { none() } // overridden by subclasses + + Expr getExpr() { none() } // overridden by subclasses +} + +private class InstructionExprNode extends ExprNodeBase, InstructionNode { + InstructionExprNode() { exprNodeShouldBeInstruction(this, _) } + + final override Expr getConvertedExpr() { exprNodeShouldBeInstruction(this, result) } + + final override Expr getExpr() { result = this.getInstruction().getUnconvertedResultExpression() } + + final override string toStringImpl() { result = this.getConvertedExpr().toString() } +} + +private class OperandExprNode extends ExprNodeBase, OperandNode { + OperandExprNode() { exprNodeShouldBeOperand(this, _) } + + final override Expr getConvertedExpr() { exprNodeShouldBeOperand(this, result) } + + final override Expr getExpr() { + result = this.getOperand().getDef().getUnconvertedResultExpression() + } + + final override string toStringImpl() { + // Avoid generating multiple `toString` results for `ArgumentNode`s + // since they have a better `toString`. + result = this.(ArgumentNode).toStringImpl() + or + not this instanceof ArgumentNode and + result = this.getConvertedExpr().toString() + } +} + +private class IndirectOperandExprNode extends ExprNodeBase, IndirectOperand { + LoadInstruction load; + + IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, load) } + + final override Expr getConvertedExpr() { exprNodeShouldBeIndirectOperand(this, result, load) } + + final override Expr getExpr() { result = load.getUnconvertedResultExpression() } + + final override string toStringImpl() { result = this.getConvertedExpr().toString() } +} + +/** + * An expression, viewed as a node in a data flow graph. + */ +class ExprNode extends Node instanceof ExprNodeBase { + /** + * Gets the non-conversion expression corresponding to this node, if any. If + * this node strictly (in the sense of `getConvertedExpr`) corresponds to a + * `Conversion`, then the result is that `Conversion`'s non-`Conversion` base + * expression. + */ + Expr getExpr() { result = super.getExpr() } + + /** + * Gets the expression corresponding to this node, if any. The returned + * expression may be a `Conversion`. + */ + Expr getConvertedExpr() { result = super.getConvertedExpr() } +} + +/** + * The value of a parameter at function entry, viewed as a node in a data + * flow graph. This includes both explicit parameters such as `x` in `f(x)` + * and implicit parameters such as `this` in `x.f()`. + * + * To match a specific kind of parameter, consider using one of the subclasses + * `ExplicitParameterNode`, `ThisParameterNode`, or + * `ParameterIndirectionNode`. + */ +class ParameterNode extends Node { + ParameterNode() { + // To avoid making this class abstract, we enumerate its values here + this.asInstruction() instanceof InitializeParameterInstruction + or + this instanceof IndirectParameterNode + } + + /** + * Holds if this node is the parameter of `f` at the specified position. The + * implicit `this` parameter is considered to have position `-1`, and + * pointer-indirection parameters are at further negative positions. + */ + predicate isParameterOf(Function f, ParameterPosition pos) { none() } // overridden by subclasses +} + +/** An explicit positional parameter, not including `this` or `...`. */ +private class ExplicitParameterNode extends ParameterNode, InstructionNode { + override InitializeParameterInstruction instr; + + ExplicitParameterNode() { exists(instr.getParameter()) } + + override predicate isParameterOf(Function f, ParameterPosition pos) { + f.getParameter(pos.(DirectPosition).getIndex()) = instr.getParameter() + } + + /** Gets the `Parameter` associated with this node. */ + Parameter getParameter() { result = instr.getParameter() } + + override string toStringImpl() { result = instr.getParameter().toString() } +} + +/** An implicit `this` parameter. */ +class ThisParameterNode extends ParameterNode, InstructionNode { + override InitializeParameterInstruction instr; + + ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable } + + override predicate isParameterOf(Function f, ParameterPosition pos) { + pos.(DirectPosition).getIndex() = -1 and instr.getEnclosingFunction() = f + } + + override string toStringImpl() { result = "this" } +} + +pragma[noinline] +private predicate indirectPostionHasArgumentIndexAndIndex( + IndirectionPosition pos, int argumentIndex, int indirectionIndex +) { + pos.getArgumentIndex() = argumentIndex and + pos.getIndirectionIndex() = indirectionIndex +} + +pragma[noinline] +private predicate indirectParameterNodeHasArgumentIndexAndIndex( + IndirectParameterNode node, int argumentIndex, int indirectionIndex +) { + node.getArgumentIndex() = argumentIndex and + node.getIndirectionIndex() = indirectionIndex +} + +/** A synthetic parameter to model the pointed-to object of a pointer parameter. */ +class ParameterIndirectionNode extends ParameterNode instanceof IndirectParameterNode { + override predicate isParameterOf(Function f, ParameterPosition pos) { + IndirectParameterNode.super.getEnclosingCallable() = f and + exists(int argumentIndex, int indirectionIndex | + indirectPostionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and + indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex) + ) + } +} + +/** + * A node associated with an object after an operation that might have + * changed its state. + * + * This can be either the argument to a callable after the callable returns + * (which might have mutated the argument), or the qualifier of a field after + * an update to the field. + * + * Nodes corresponding to AST elements, for example `ExprNode`, usually refer + * to the value before the update with the exception of `ClassInstanceExpr`, + * which represents the value after the constructor has run. + */ +abstract class PostUpdateNode extends Node { + /** + * Gets the node before the state update. + */ + abstract Node getPreUpdateNode(); +} + +/** + * The base class for nodes that perform "partial definitions". + * + * In contrast to a normal "definition", which provides a new value for + * something, a partial definition is an expression that may affect a + * value, but does not necessarily replace it entirely. For example: + * ``` + * x.y = 1; // a partial definition of the object `x`. + * x.y.z = 1; // a partial definition of the object `x.y` and `x`. + * x.setY(1); // a partial definition of the object `x`. + * setY(&x); // a partial definition of the object `x`. + * ``` + */ +abstract private class PartialDefinitionNode extends PostUpdateNode { + abstract Expr getDefinedExpr(); +} + +/** + * A node that represents the value of a variable after a function call that + * may have changed the variable because it's passed by reference. + * + * A typical example would be a call `f(&x)`. Firstly, there will be flow into + * `x` from previous definitions of `x`. Secondly, there will be a + * `DefinitionByReferenceNode` to represent the value of `x` after the call has + * returned. This node will have its `getArgument()` equal to `&x` and its + * `getVariableAccess()` equal to `x`. + */ +class DefinitionByReferenceNode extends IndirectArgumentOutNode { + /** Gets the unconverted argument corresponding to this node. */ + Expr getArgument() { result = this.getAddressOperand().getDef().getUnconvertedResultExpression() } + + /** Gets the parameter through which this value is assigned. */ + Parameter getParameter() { + result = this.getCallInstruction().getStaticCallTarget().getParameter(this.getArgumentIndex()) + } +} + +/** + * A `Node` corresponding to a variable in the program, as opposed to the + * value of that variable at some particular point. This can be used for + * modeling flow in and out of global variables. + */ +class VariableNode extends Node, TVariableNode { + Variable v; + + VariableNode() { this = TVariableNode(v) } + + /** Gets the variable corresponding to this node. */ + Variable getVariable() { result = v } + + override Declaration getFunction() { none() } + + override Declaration getEnclosingCallable() { + // When flow crosses from one _enclosing callable_ to another, the + // interprocedural data-flow library discards call contexts and inserts a + // node in the big-step relation used for human-readable path explanations. + // Therefore we want a distinct enclosing callable for each `VariableNode`, + // and that can be the `Variable` itself. + result = v + } + + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } + + final override Location getLocationImpl() { result = v.getLocation() } + + override string toStringImpl() { result = v.toString() } +} + +/** + * Gets the node corresponding to `instr`. + */ +InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr } + +/** + * Gets the node corresponding to `operand`. + */ +OperandNode operandNode(Operand operand) { result.getOperand() = operand } + +/** + * Gets the `Node` corresponding to the value of evaluating `e` or any of its + * conversions. There is no result if `e` is a `Conversion`. For data flowing + * _out of_ an expression, like when an argument is passed by reference, use + * `definitionByReferenceNodeFromArgument` instead. + */ +ExprNode exprNode(Expr e) { result.getExpr() = e } + +/** + * Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may + * be a `Conversion`. For data flowing _out of_ an expression, like when an + * argument is passed by reference, use + * `definitionByReferenceNodeFromArgument` instead. + */ +ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e } + +/** + * Gets the `Node` corresponding to the value of `p` at function entry. + */ +ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p } + +/** + * Gets the `Node` corresponding to a definition by reference of the variable + * that is passed as unconverted `argument` of a call. + */ +DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) { + result.getArgument() = argument +} + +/** Gets the `VariableNode` corresponding to the variable `v`. */ +VariableNode variableNode(Variable v) { result.getVariable() = v } + +/** + * DEPRECATED: See UninitializedNode. + * + * Gets the `Node` corresponding to the value of an uninitialized local + * variable `v`. + */ +Node uninitializedNode(LocalVariable v) { none() } + +/** + * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ +predicate localFlowStep = simpleLocalFlowStep/2; + +private predicate indirectionOperandFlow(IndirectOperand nodeFrom, Node nodeTo) { + // Reduce the indirection count by 1 if we're passing through a `LoadInstruction`. + exists(int ind, LoadInstruction load | + hasOperandAndIndex(nodeFrom, load.getSourceAddressOperand(), ind) and + nodeHasInstruction(nodeTo, load, ind - 1) + ) + or + // If an operand flows to an instruction, then the indirection of + // the operand also flows to the indirction of the instruction. + exists(Operand operand, Instruction instr, int indirectionIndex | + simpleInstructionLocalFlowStep(operand, instr) and + hasOperandAndIndex(nodeFrom, operand, indirectionIndex) and + hasInstructionAndIndex(nodeTo, instr, indirectionIndex) + ) + or + // If there's indirect flow to an operand, then there's also indirect + // flow to the operand after applying some pointer arithmetic. + exists(PointerArithmeticInstruction pointerArith, int indirectionIndex | + hasOperandAndIndex(nodeFrom, pointerArith.getAnOperand(), indirectionIndex) and + hasInstructionAndIndex(nodeTo, pointerArith, indirectionIndex) + ) +} + +pragma[noinline] +predicate hasOperandAndIndex(IndirectOperand indirectOperand, Operand operand, int indirectionIndex) { + indirectOperand.getOperand() = operand and + indirectOperand.getIndirectionIndex() = indirectionIndex +} + +pragma[noinline] +predicate hasInstructionAndIndex( + IndirectInstruction indirectInstr, Instruction instr, int indirectionIndex +) { + indirectInstr.getInstruction() = instr and + indirectInstr.getIndirectionIndex() = indirectionIndex +} + +private predicate indirectionInstructionFlow(IndirectInstruction nodeFrom, IndirectOperand nodeTo) { + // If there's flow from an instruction to an operand, then there's also flow from the + // indirect instruction to the indirect operand. + exists(Operand operand, Instruction instr, int indirectionIndex | + simpleOperandLocalFlowStep(pragma[only_bind_into](instr), pragma[only_bind_into](operand)) + | + hasOperandAndIndex(nodeTo, operand, indirectionIndex) and + hasInstructionAndIndex(nodeFrom, instr, indirectionIndex) + ) +} + +/** + * INTERNAL: do not use. + * + * This is the local flow predicate that's used as a building block in global + * data flow. It may have less flow than the `localFlowStep` predicate. + */ +predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + // Post update node -> Node flow + Ssa::ssaFlow(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + // Def-use/Use-use flow + Ssa::ssaFlow(nodeFrom, nodeTo) + or + // Operand -> Instruction flow + simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + // Instruction -> Operand flow + simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) + or + // Phi node -> Node flow + Ssa::fromPhiNode(nodeFrom, nodeTo) + or + // Indirect operand -> (indirect) instruction flow + indirectionOperandFlow(nodeFrom, nodeTo) + or + // Indirect instruction -> indirect operand flow + indirectionInstructionFlow(nodeFrom, nodeTo) + or + // Flow through modeled functions + modelFlow(nodeFrom, nodeTo) + or + // Reverse flow: data that flows from the definition node back into the indirection returned + // by a function. This allows data to flow 'in' through references returned by a modeled + // function such as `operator[]`. + exists(Operand address, int indirectionIndex | + nodeHasOperand(nodeTo.(IndirectReturnOutNode), address, indirectionIndex) + | + exists(StoreInstruction store | + nodeHasInstruction(nodeFrom, store, indirectionIndex - 1) and + store.getDestinationAddressOperand() = address + ) + or + Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex - 1) + ) +} + +pragma[noinline] +private predicate getAddressType(LoadInstruction load, Type t) { + exists(Instruction address | + address = load.getSourceAddress() and + t = address.getResultType() + ) +} + +/** + * Like the AST dataflow library, we want to conflate the address and value of a reference. This class + * represents the `LoadInstruction` that is generated from a reference dereference. + */ +private class ReferenceDereferenceInstruction extends LoadInstruction { + ReferenceDereferenceInstruction() { + exists(ReferenceType ref | + getAddressType(this, ref) and + this.getResultType() = ref.getBaseType() + ) + } +} + +private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { + // Treat all conversions as flow, even conversions between different numeric types. + conversionFlow(opFrom, iTo, false) + or + iTo.(CopyInstruction).getSourceValueOperand() = opFrom + or + // Conflate references and values like in AST dataflow. + iTo.(ReferenceDereferenceInstruction).getSourceAddressOperand() = opFrom +} + +private predicate simpleOperandLocalFlowStep(Instruction iFrom, Operand opTo) { + not opTo instanceof MemoryOperand and + opTo.getDef() = iFrom +} + +private predicate modelFlow(Node nodeFrom, Node nodeTo) { + exists( + CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut + | + call.getStaticCallTarget() = func and + func.hasDataFlow(modelIn, modelOut) + | + nodeFrom = callInput(call, modelIn) and + nodeTo = callOutput(call, modelOut) + or + exists(int d | + nodeFrom = callInput(call, modelIn, d) and + nodeTo = callOutput(call, modelOut, d) + ) + ) +} + +/** + * Holds if data flows from `source` to `sink` in zero or more local + * (intra-procedural) steps. + */ +pragma[inline] +predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } + +/** + * Holds if data can flow from `i1` to `i2` in zero or more + * local (intra-procedural) steps. + */ +pragma[inline] +predicate localInstructionFlow(Instruction e1, Instruction e2) { + localFlow(instructionNode(e1), instructionNode(e2)) +} + +/** + * Holds if data can flow from `e1` to `e2` in zero or more + * local (intra-procedural) steps. + */ +pragma[inline] +predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) } + +cached +private newtype TContent = + TFieldContent(Field f, int indirectionIndex) { + indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(f.getUnspecifiedType())] and + // Reads and writes of union fields are tracked using `UnionContent`. + not f.getDeclaringType() instanceof Union + } or + TUnionContent(Union u, int indirectionIndex) { + // We key `UnionContent` by the union instead of its fields since a write to one + // field can be read by any read of the union's fields. + indirectionIndex = + [1 .. max(Ssa::getMaxIndirectionsForType(u.getAField().getUnspecifiedType()))] + } or + TCollectionContent() or // Not used in C/C++ + TArrayContent() // Not used in C/C++. + +/** + * 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 a non-union instance field. */ +class FieldContent extends Content, TFieldContent { + Field f; + int indirectionIndex; + + FieldContent() { this = TFieldContent(f, indirectionIndex) } + + override string toString() { + indirectionIndex = 1 and result = f.toString() + or + indirectionIndex > 1 and result = f.toString() + " indirection" + } + + Field getField() { result = f } + + pragma[inline] + int getIndirectionIndex() { + pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) + } +} + +/** A reference through an instance field of a union. */ +class UnionContent extends Content, TUnionContent { + Union u; + int indirectionIndex; + + UnionContent() { this = TUnionContent(u, indirectionIndex) } + + override string toString() { + indirectionIndex = 1 and result = u.toString() + or + indirectionIndex > 1 and result = u.toString() + " indirection" + } + + Field getAField() { result = u.getAField() } + + pragma[inline] + int getIndirectionIndex() { + pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) + } +} + +/** 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 = "" } +} + +/** + * An entity that represents a set of `Content`s. + * + * The set may be interpreted differently depending on whether it is + * stored into (`getAStoreContent`) or read from (`getAReadContent`). + */ +class ContentSet instanceof Content { + /** Gets a content that may be stored into when storing into this set. */ + Content getAStoreContent() { result = this } + + /** Gets a content that may be read from when reading from this set. */ + Content getAReadContent() { result = this } + + /** Gets a textual representation of this content set. */ + string toString() { result = super.toString() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + super.hasLocationInfo(path, sl, sc, el, ec) + } +} + +private IRBlock getBasicBlock(Node node) { + node.asInstruction().getBlock() = result + or + node.asOperand().getUse().getBlock() = result + or + node.(SsaPhiNode).getPhiNode().getBasicBlock() = result + or + node.(IndirectOperand).getOperand().getUse().getBlock() = result + or + node.(IndirectInstruction).getInstruction().getBlock() = result + or + result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode()) +} + +/** + * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. + * + * The expression `e` is expected to be a syntactic part of the guard `g`. + * For example, the guard `g` might be a call `isSafe(x)` and the expression `e` + * the argument `x`. + */ +signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch); + +/** + * Provides a set of barrier nodes for a guard that validates an expression. + * + * This is expected to be used in `isBarrier`/`isSanitizer` definitions + * in data flow and taint tracking. + */ +module BarrierGuard { + /** Gets a node that is safely guarded by the given guard check. */ + ExprNode getABarrierNode() { + exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | + e = value.getAnInstruction().getConvertedResultExpression() and + result.getConvertedExpr() = e and + guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and + g.controls(getBasicBlock(result), edge) + ) + } +} + +/** + * Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`. + */ +signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch); + +/** + * Provides a set of barrier nodes for a guard that validates an instruction. + * + * This is expected to be used in `isBarrier`/`isSanitizer` definitions + * in data flow and taint tracking. + */ +module InstructionBarrierGuard { + /** Gets a node that is safely guarded by the given guard check. */ + ExprNode getABarrierNode() { + exists(IRGuardCondition g, ValueNumber value, boolean edge | + instructionGuardChecks(g, value.getAnInstruction(), edge) and + result.asInstruction() = value.getAnInstruction() and + g.controls(result.asInstruction().getBlock(), edge) + ) + } +} + +/** + * DEPRECATED: Use `BarrierGuard` module instead. + * + * A guard that validates some instruction. + * + * To use this in a configuration, extend the class and provide a + * characteristic predicate precisely specifying the guard, and override + * `checks` to specify what is being validated and in which branch. + * + * It is important that all extending classes in scope are disjoint. + */ +deprecated class BarrierGuard extends IRGuardCondition { + /** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */ + predicate checksInstr(Instruction instr, boolean b) { none() } + + /** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */ + predicate checks(Expr e, boolean b) { none() } + + /** Gets a node guarded by this guard. */ + final Node getAGuardedNode() { + exists(ValueNumber value, boolean edge | + ( + this.checksInstr(value.getAnInstruction(), edge) + or + this.checks(value.getAnInstruction().getConvertedResultExpression(), edge) + ) and + result.asInstruction() = value.getAnInstruction() and + this.controls(result.asInstruction().getBlock(), edge) + ) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll new file mode 100644 index 00000000000..c302c6ef878 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll @@ -0,0 +1,93 @@ +/** + * Provides predicates for mapping the `FunctionInput` and `FunctionOutput` + * classes used in function models to the corresponding instructions. + */ + +private import semmle.code.cpp.ir.IR +private import experimental.semmle.code.cpp.ir.dataflow.DataFlow +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import SsaInternals as Ssa + +/** + * Gets the instruction that goes into `input` for `call`. + */ +DataFlow::Node callInput(CallInstruction call, FunctionInput input) { + // An argument or qualifier + exists(int index | + result.asOperand() = call.getArgumentOperand(index) and + input.isParameterOrQualifierAddress(index) + ) + or + // A value pointed to by an argument or qualifier + exists(int index, int indirectionIndex | + hasOperandAndIndex(result, call.getArgumentOperand(index), indirectionIndex) and + input.isParameterDerefOrQualifierObject(index, indirectionIndex) + ) + or + exists(int ind | + result = getIndirectReturnOutNode(call, ind) and + input.isReturnValueDeref(ind) + ) +} + +/** + * Gets the instruction that holds the `output` for `call`. + */ +Node callOutput(CallInstruction call, FunctionOutput output) { + // The return value + result.asInstruction() = call and + output.isReturnValue() + or + // The side effect of a call on the value pointed to by an argument or qualifier + exists(int index, int indirectionIndex | + result.(IndirectArgumentOutNode).getArgumentIndex() = index and + result.(IndirectArgumentOutNode).getIndirectionIndex() + 1 = indirectionIndex and + result.(IndirectArgumentOutNode).getCallInstruction() = call and + output.isParameterDerefOrQualifierObject(index, indirectionIndex) + ) + or + exists(int ind | + result = getIndirectReturnOutNode(call, ind) and + output.isReturnValueDeref(ind) + ) +} + +DataFlow::Node callInput(CallInstruction call, FunctionInput input, int d) { + exists(DataFlow::Node n | n = callInput(call, input) and d > 0 | + // An argument or qualifier + hasOperandAndIndex(result, n.asOperand(), d) + or + exists(Operand operand, int indirectionIndex | + // A value pointed to by an argument or qualifier + hasOperandAndIndex(n, operand, indirectionIndex) and + hasOperandAndIndex(result, operand, indirectionIndex + d) + ) + ) +} + +private IndirectReturnOutNode getIndirectReturnOutNode(CallInstruction call, int d) { + result.getCallInstruction() = call and + result.getIndirectionIndex() = d +} + +/** + * Gets the instruction that holds the `output` for `call`. + */ +bindingset[d] +Node callOutput(CallInstruction call, FunctionOutput output, int d) { + exists(DataFlow::Node n | n = callOutput(call, output) and d > 0 | + // The return value + result = getIndirectReturnOutNode(n.asInstruction(), d) + or + // If there isn't an indirect out node for the call with indirection `d` then + // we conflate this with the underlying `CallInstruction`. + not exists(getIndirectReturnOutNode(call, d)) and + n.asInstruction() = result.asInstruction() + or + // The side effect of a call on the value pointed to by an argument or qualifier + exists(Operand operand, int indirectionIndex | + Ssa::outNodeHasAddressAndIndex(n, operand, indirectionIndex) and + Ssa::outNodeHasAddressAndIndex(result, operand, indirectionIndex + d) + ) + ) +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll new file mode 100644 index 00000000000..7359656e5a4 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll @@ -0,0 +1,136 @@ +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import PrintIRUtilities + +/** + * Gets the local dataflow from other nodes in the same function to this node. + */ +private string getFromFlow(DataFlow::Node useNode, int order1, int order2) { + exists(DataFlow::Node defNode, string prefix | + ( + simpleLocalFlowStep(defNode, useNode) and prefix = "" + or + any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and + defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and + prefix = "+" + ) and + if defNode.asInstruction() = useNode.asOperand().getAnyDef() + then + // Shorthand for flow from the def of this operand. + result = prefix + "def" and + order1 = -1 and + order2 = 0 + else + if defNode.asOperand().getUse() = useNode.asInstruction() + then + // Shorthand for flow from an operand of this instruction + result = prefix + defNode.asOperand().getDumpId() and + order1 = -1 and + order2 = defNode.asOperand().getDumpSortOrder() + else result = prefix + nodeId(defNode, order1, order2) + ) +} + +/** + * Gets the local dataflow from this node to other nodes in the same function. + */ +private string getToFlow(DataFlow::Node defNode, int order1, int order2) { + exists(DataFlow::Node useNode, string prefix | + ( + simpleLocalFlowStep(defNode, useNode) and prefix = "" + or + any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and + defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and + prefix = "+" + ) and + if useNode.asInstruction() = defNode.asOperand().getUse() + then + // Shorthand for flow to this operand's instruction. + result = prefix + "result" and + order1 = -1 and + order2 = 0 + else result = prefix + nodeId(useNode, order1, order2) + ) +} + +/** + * Gets the properties of the dataflow node `node`. + */ +private string getNodeProperty(DataFlow::Node node, string key) { + // List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow + // out of this node is printed as `@->dest`. + key = "flow" and + result = + strictconcat(string flow, boolean to, int order1, int order2 | + flow = getFromFlow(node, order1, order2) + "->@" and to = false + or + flow = "@->" + getToFlow(node, order1, order2) and to = true + | + flow, ", " order by to, order1, order2, flow + ) + or + // Is this node a dataflow sink? + key = "sink" and + any(DataFlow::Configuration cfg).isSink(node) and + result = "true" + or + // Is this node a dataflow source? + key = "source" and + any(DataFlow::Configuration cfg).isSource(node) and + result = "true" + or + // Is this node a dataflow barrier, and if so, what kind? + key = "barrier" and + result = + strictconcat(string kind | + any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full" + or + any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in" + or + any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out" + | + kind, ", " + ) + or + // Is there partial flow from a source to this node? + // This property will only be emitted if partial flow is enabled by overriding + // `DataFlow::Configration::explorationLimit()`. + key = "pflow" and + result = + strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist, + int order1, int order2 | + any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and + destNode.getNode() = node and + // Only print flow from a source in the same function. + sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable() + | + nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", " + order by + order1, order2, dist desc + ) +} + +/** + * Property provider for local IR dataflow. + */ +class LocalFlowPropertyProvider extends IRPropertyProvider { + override string getOperandProperty(Operand operand, string key) { + exists(DataFlow::Node node | + operand = node.asOperand() and + result = getNodeProperty(node, key) + ) + } + + override string getInstructionProperty(Instruction instruction, string key) { + exists(DataFlow::Node node | + instruction = node.asInstruction() and + result = getNodeProperty(node, key) + ) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll new file mode 100644 index 00000000000..8c318216217 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll @@ -0,0 +1,33 @@ +/** + * Print the dataflow local store steps in IR dumps. + */ + +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate +private import PrintIRUtilities + +/** + * Property provider for local IR dataflow store steps. + */ +class LocalFlowPropertyProvider extends IRPropertyProvider { + override string getInstructionProperty(Instruction instruction, string key) { + exists(DataFlow::Node objectNode, Content content | + key = "content[" + content.toString() + "]" and + instruction = objectNode.asInstruction() and + result = + strictconcat(string element, DataFlow::Node fieldNode | + storeStep(fieldNode, content, objectNode) and + element = nodeId(fieldNode, _, _) + | + element, ", " + ) + ) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll new file mode 100644 index 00000000000..5fc15cf986c --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll @@ -0,0 +1,39 @@ +/** + * Shared utilities used when printing dataflow annotations in IR dumps. + */ + +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow + +/** + * Gets a short ID for an IR dataflow node. + * - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`). + * - For `Operand`s, this is the label of the operand, prefixed with the result ID of the + * instruction and a dot (e.g. `m128.left`). + * - For `Variable`s, this is the qualified name of the variable. + */ +string nodeId(DataFlow::Node node, int order1, int order2) { + exists(Instruction instruction | instruction = node.asInstruction() | + result = instruction.getResultId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + exists(Operand operand, Instruction instruction | + operand = node.asOperand() and + instruction = operand.getUse() + | + result = instruction.getResultId() + "." + operand.getDumpId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + result = "var(" + node.asVariable().getQualifiedName() + ")" and + order1 = 1000000 and + order2 = 0 +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll new file mode 100644 index 00000000000..61ff5707d77 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll @@ -0,0 +1,547 @@ +private import codeql.ssa.Ssa as SsaImplCommon +private import semmle.code.cpp.ir.IR +private import DataFlowUtil +private import DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.cpp.models.interfaces.Allocation as Alloc +private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow +private import semmle.code.cpp.ir.internal.IRCppLanguage +private import DataFlowPrivate +private import ssa0.SsaInternals as SsaInternals0 +import SsaInternalsCommon + +private module SourceVariables { + int getMaxIndirectionForIRVariable(IRVariable var) { + exists(Type type, boolean isGLValue | + var.getLanguageType().hasType(type, isGLValue) and + if isGLValue = true + then result = 1 + getMaxIndirectionsForType(type) + else result = getMaxIndirectionsForType(type) + ) + } + + class BaseSourceVariable = SsaInternals0::BaseSourceVariable; + + class BaseIRVariable = SsaInternals0::BaseIRVariable; + + class BaseCallVariable = SsaInternals0::BaseCallVariable; + + cached + private newtype TSourceVariable = + TSourceIRVariable(BaseIRVariable baseVar, int ind) { + ind = [0 .. getMaxIndirectionForIRVariable(baseVar.getIRVariable())] + } or + TCallVariable(AllocationInstruction call, int ind) { + ind = [0 .. countIndirectionsForCppType(getResultLanguageType(call))] + } + + abstract class SourceVariable extends TSourceVariable { + int ind; + + bindingset[ind] + SourceVariable() { any() } + + abstract string toString(); + + int getIndirection() { result = ind } + + abstract BaseSourceVariable getBaseVariable(); + } + + class SourceIRVariable extends SourceVariable, TSourceIRVariable { + BaseIRVariable var; + + SourceIRVariable() { this = TSourceIRVariable(var, ind) } + + IRVariable getIRVariable() { result = var.getIRVariable() } + + override BaseIRVariable getBaseVariable() { result.getIRVariable() = this.getIRVariable() } + + override string toString() { + ind = 0 and + result = this.getIRVariable().toString() + or + ind > 0 and + result = this.getIRVariable().toString() + " indirection" + } + } + + class CallVariable extends SourceVariable, TCallVariable { + AllocationInstruction call; + + CallVariable() { this = TCallVariable(call, ind) } + + AllocationInstruction getCall() { result = call } + + override BaseCallVariable getBaseVariable() { result.getCallInstruction() = call } + + override string toString() { + ind = 0 and + result = "Call" + or + ind > 0 and + result = "Call indirection" + } + } +} + +import SourceVariables + +predicate hasIndirectOperand(Operand op, int indirectionIndex) { + exists(CppType type, int m | + not ignoreOperand(op) and + type = getLanguageType(op) and + m = countIndirectionsForCppType(type) and + indirectionIndex = [1 .. m] + ) +} + +predicate hasIndirectInstruction(Instruction instr, int indirectionIndex) { + exists(CppType type, int m | + not ignoreInstruction(instr) and + type = getResultLanguageType(instr) and + m = countIndirectionsForCppType(type) and + indirectionIndex = [1 .. m] + ) +} + +cached +private newtype TDefOrUseImpl = + TDefImpl(Operand address, int indirectionIndex) { + isDef(_, _, address, _, _, indirectionIndex) and + // We only include the definition if the SSA pruning stage + // concluded that the definition is live after the write. + any(SsaInternals0::Def def).getAddressOperand() = address + } or + TUseImpl(Operand operand, int indirectionIndex) { + isUse(_, operand, _, _, indirectionIndex) and + not isDef(_, _, operand, _, _, _) + } + +abstract private class DefOrUseImpl extends TDefOrUseImpl { + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets the block of this definition or use. */ + abstract IRBlock getBlock(); + + /** Holds if this definition or use has index `index` in block `block`. */ + abstract predicate hasIndexInBlock(IRBlock block, int index); + + final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) { + this.hasIndexInBlock(block, index) and + sv = this.getSourceVariable() + } + + /** Gets the location of this element. */ + abstract Cpp::Location getLocation(); + + /** + * Gets the index (i.e., the number of loads required) of this + * definition or use. + * + * Note that this is _not_ the definition's (or use's) index in + * the enclosing basic block. To obtain this index, use + * `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`. + */ + abstract int getIndirectionIndex(); + + /** + * Gets the instruction that computes the base of this definition or use. + * This is always a `VariableAddressInstruction` or an `AllocationInstruction`. + */ + abstract Instruction getBase(); + + final BaseSourceVariable getBaseSourceVariable() { + exists(IRVariable var | + result.(BaseIRVariable).getIRVariable() = var and + instructionHasIRVariable(this.getBase(), var) + ) + or + result.(BaseCallVariable).getCallInstruction() = this.getBase() + } + + /** Gets the variable that is defined or used. */ + final SourceVariable getSourceVariable() { + exists(BaseSourceVariable v, int ind | + sourceVariableHasBaseAndIndex(result, v, ind) and + defOrUseHasSourceVariable(this, v, ind) + ) + } +} + +pragma[noinline] +private predicate instructionHasIRVariable(VariableAddressInstruction vai, IRVariable var) { + vai.getIRVariable() = var +} + +private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv, int ind) { + defHasSourceVariable(defOrUse, bv, ind) + or + useHasSourceVariable(defOrUse, bv, ind) +} + +pragma[noinline] +private predicate defHasSourceVariable(DefImpl def, BaseSourceVariable bv, int ind) { + bv = def.getBaseSourceVariable() and + ind = def.getIndirection() +} + +pragma[noinline] +private predicate useHasSourceVariable(UseImpl use, BaseSourceVariable bv, int ind) { + bv = use.getBaseSourceVariable() and + ind = use.getIndirection() +} + +pragma[noinline] +private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVariable bv, int ind) { + v.getBaseVariable() = bv and + v.getIndirection() = ind +} + +class DefImpl extends DefOrUseImpl, TDefImpl { + Operand address; + int ind; + + DefImpl() { this = TDefImpl(address, ind) } + + override Instruction getBase() { isDef(_, _, address, result, _, _) } + + Operand getAddressOperand() { result = address } + + int getIndirection() { isDef(_, _, address, _, result, ind) } + + override int getIndirectionIndex() { result = ind } + + Instruction getDefiningInstruction() { isDef(_, result, address, _, _, _) } + + override string toString() { result = "DefImpl" } + + override IRBlock getBlock() { result = this.getDefiningInstruction().getBlock() } + + override Cpp::Location getLocation() { result = this.getDefiningInstruction().getLocation() } + + final override predicate hasIndexInBlock(IRBlock block, int index) { + this.getDefiningInstruction() = block.getInstruction(index) + } + + predicate isCertain() { isDef(true, _, address, _, _, ind) } +} + +class UseImpl extends DefOrUseImpl, TUseImpl { + Operand operand; + int ind; + + UseImpl() { this = TUseImpl(operand, ind) } + + Operand getOperand() { result = operand } + + override string toString() { result = "UseImpl" } + + final override predicate hasIndexInBlock(IRBlock block, int index) { + operand.getUse() = block.getInstruction(index) + } + + final override IRBlock getBlock() { result = operand.getUse().getBlock() } + + final override Cpp::Location getLocation() { result = operand.getLocation() } + + final int getIndirection() { isUse(_, operand, _, result, ind) } + + override int getIndirectionIndex() { result = ind } + + override Instruction getBase() { isUse(_, operand, result, _, ind) } + + predicate isCertain() { isUse(true, operand, _, _, ind) } +} + +/** + * Holds if `defOrUse1` is a definition which is first read by `use`, + * or if `defOrUse1` is a use and `use` is a next subsequent use. + * + * In both cases, `use` can either be an explicit use written in the + * source file, or it can be a phi node as computed by the SSA library. + */ +predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) { + exists(IRBlock bb1, int i1, SourceVariable v | + defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v) + | + exists(IRBlock bb2, int i2 | + adjacentDefRead(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1), + pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) + | + use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v) + ) + or + exists(PhiNode phi | + lastRefRedef(_, bb1, i1, phi) and + use.asPhi() = phi and + phi.getSourceVariable() = pragma[only_bind_into](v) + ) + ) +} + +private predicate useToNode(UseOrPhi use, Node nodeTo) { + exists(UseImpl useImpl | + useImpl = use.asDefOrUse() and + nodeHasOperand(nodeTo, useImpl.getOperand(), useImpl.getIndirectionIndex()) + ) + or + nodeTo.(SsaPhiNode).getPhiNode() = use.asPhi() +} + +pragma[noinline] +predicate outNodeHasAddressAndIndex( + IndirectArgumentOutNode out, Operand address, int indirectionIndex +) { + out.getAddressOperand() = address and + out.getIndirectionIndex() = indirectionIndex +} + +private predicate defToNode(Node nodeFrom, Def def) { + nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex()) +} + +private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) { + // Node -> Def + defToNode(nodeFrom, defOrUse) + or + // Node -> Use + useToNode(defOrUse, nodeFrom) +} + +/** + * Perform a single conversion-like step from `nFrom` to `nTo`. This relation + * only holds when there is no use-use relation out of `nTo`. + */ +private predicate indirectConversionFlowStep(Node nFrom, Node nTo) { + not exists(UseOrPhi defOrUse | + nodeToDefOrUse(nTo, defOrUse) and + adjacentDefRead(defOrUse, _) + ) and + exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr | + hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and + hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and + instr = op2.getDef() and + conversionFlow(op1, instr, _) + ) +} + +/** + * The reason for this predicate is a bit annoying: + * We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA + * variable `x` as a use of `x` since this creates taint-flow in the following example: + * ```c + * int x = array[source] + * sink(*array) + * ``` + * This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the + * result of the instruction, and into the `IndirectOperand` that represents the value of `*array`. + * Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`. + * + * So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the + * first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`. + */ +private predicate adjustForPointerArith(Node nodeFrom, UseOrPhi use) { + nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and + exists(DefOrUse defOrUse, Node adjusted | + indirectConversionFlowStep*(adjusted, nodeFrom) and + nodeToDefOrUse(adjusted, defOrUse) and + adjacentDefRead(defOrUse, use) + ) +} + +/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */ +predicate ssaFlow(Node nodeFrom, Node nodeTo) { + // `nodeFrom = any(PostUpdateNode pun).getPreUpdateNode()` is implied by adjustedForPointerArith. + exists(UseOrPhi use | + adjustForPointerArith(nodeFrom, use) and + useToNode(use, nodeTo) + ) + or + not nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and + exists(DefOrUse defOrUse1, UseOrPhi use | + nodeToDefOrUse(nodeFrom, defOrUse1) and + adjacentDefRead(defOrUse1, use) and + useToNode(use, nodeTo) + ) +} + +/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */ +predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) { + exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use | + phi = nodeFrom.getPhiNode() and + phi.definesAt(sv, bb1, i1) and + useToNode(use, nodeTo) + | + exists(IRBlock bb2, int i2 | + use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and + adjacentDefRead(phi, bb1, i1, bb2, i2) + ) + or + exists(PhiNode phiTo | + lastRefRedef(phi, _, _, phiTo) and + nodeTo.(SsaPhiNode).getPhiNode() = phiTo + ) + ) +} + +private SsaInternals0::SourceVariable getOldSourceVariable(SourceVariable v) { + v.getBaseVariable().(BaseIRVariable).getIRVariable() = + result.getBaseVariable().(SsaInternals0::BaseIRVariable).getIRVariable() + or + v.getBaseVariable().(BaseCallVariable).getCallInstruction() = + result.getBaseVariable().(SsaInternals0::BaseCallVariable).getCallInstruction() +} + +/** + * Holds if there is a write at index `i` in basic block `bb` to variable `v` that's + * subsequently read (as determined by the SSA pruning stage). + */ +private predicate variableWriteCand(IRBlock bb, int i, SourceVariable v) { + exists(SsaInternals0::Def def, SsaInternals0::SourceVariable v0 | + def.asDefOrUse().hasIndexInBlock(bb, i, v0) and + v0 = getOldSourceVariable(v) + ) +} + +private module SsaInput implements SsaImplCommon::InputSig { + import InputSigCommon + import SourceVariables + + /** + * Holds if the `i`'th write in block `bb` writes to the variable `v`. + * `certain` is `true` if the write is guaranteed to overwrite the entire variable. + */ + predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) { + DataFlowImplCommon::forceCachingInSameStage() and + variableWriteCand(bb, i, v) and + exists(DefImpl def | def.hasIndexInBlock(bb, i, v) | + if def.isCertain() then certain = true else certain = false + ) + } + + /** + * Holds if the `i`'th read in block `bb` reads to the variable `v`. + * `certain` is `true` if the read is guaranteed. For C++, this is always the case. + */ + predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) { + exists(UseImpl use | use.hasIndexInBlock(bb, i, v) | + if use.isCertain() then certain = true else certain = false + ) + } +} + +/** + * The final SSA predicates used for dataflow purposes. + */ +cached +module SsaCached { + /** + * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read + * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a + * path between them without any read of `def`. + */ + cached + predicate adjacentDefRead(Definition def, IRBlock bb1, int i1, IRBlock bb2, int i2) { + SsaImpl::adjacentDefRead(def, bb1, i1, bb2, i2) + } + + /** + * Holds if the node at index `i` in `bb` is a last reference to SSA definition + * `def`. The reference is last because it can reach another write `next`, + * without passing through another read or write. + */ + cached + predicate lastRefRedef(Definition def, IRBlock bb, int i, Definition next) { + SsaImpl::lastRefRedef(def, bb, i, next) + } +} + +cached +private newtype TSsaDefOrUse = + TDefOrUse(DefOrUseImpl defOrUse) { + defOrUse instanceof UseImpl + or + // Like in the pruning stage, we only include definition that's live after the + // write as the final definitions computed by SSA. + exists(Definition def, SourceVariable sv, IRBlock bb, int i | + def.definesAt(sv, bb, i) and + defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv) + ) + } or + TPhi(PhiNode phi) + +abstract private class SsaDefOrUse extends TSsaDefOrUse { + string toString() { none() } + + DefOrUseImpl asDefOrUse() { none() } + + PhiNode asPhi() { none() } + + abstract Location getLocation(); +} + +class DefOrUse extends TDefOrUse, SsaDefOrUse { + DefOrUseImpl defOrUse; + + DefOrUse() { this = TDefOrUse(defOrUse) } + + final override DefOrUseImpl asDefOrUse() { result = defOrUse } + + final override Location getLocation() { result = defOrUse.getLocation() } + + final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() } + + override string toString() { result = defOrUse.toString() } +} + +class Phi extends TPhi, SsaDefOrUse { + PhiNode phi; + + Phi() { this = TPhi(phi) } + + final override PhiNode asPhi() { result = phi } + + final override Location getLocation() { result = phi.getBasicBlock().getLocation() } + + override string toString() { result = "Phi" } +} + +class UseOrPhi extends SsaDefOrUse { + UseOrPhi() { + this.asDefOrUse() instanceof UseImpl + or + this instanceof Phi + } + + final override Location getLocation() { + result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation() + } +} + +class Def extends DefOrUse { + override DefImpl defOrUse; + + Operand getAddressOperand() { result = defOrUse.getAddressOperand() } + + Instruction getAddress() { result = this.getAddressOperand().getDef() } + + /** + * This predicate ensures that joins go from `defOrUse` to the result + * instead of the other way around. + */ + pragma[inline] + int getIndirectionIndex() { + pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirectionIndex() + } + + Instruction getDefiningInstruction() { result = defOrUse.getDefiningInstruction() } +} + +private module SsaImpl = SsaImplCommon::Make; + +class PhiNode = SsaImpl::PhiNode; + +class Definition = SsaImpl::Definition; + +import SsaCached diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll new file mode 100644 index 00000000000..36ab036c4e5 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll @@ -0,0 +1,268 @@ +import cpp as Cpp +import semmle.code.cpp.ir.IR +import semmle.code.cpp.ir.internal.IRCppLanguage +private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects +private import DataFlowImplCommon as DataFlowImplCommon +private import DataFlowUtil + +/** + * Holds if `operand` is an operand that is not used by the dataflow library. + * Ignored operands are not recognizd as uses by SSA, and they don't have a + * corresponding `(Indirect)OperandNode`. + */ +predicate ignoreOperand(Operand operand) { + operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() +} + +/** + * Holds if `instr` is an instruction that is not used by the dataflow library. + * Ignored instructions are not recognized as reads/writes by SSA, and they + * don't have a corresponding `(Indirect)InstructionNode`. + */ +predicate ignoreInstruction(Instruction instr) { + DataFlowImplCommon::forceCachingInSameStage() and + ( + instr instanceof WriteSideEffectInstruction or + instr instanceof PhiInstruction or + instr instanceof ReadSideEffectInstruction or + instr instanceof ChiInstruction or + instr instanceof InitializeIndirectionInstruction + ) +} + +/** + * Gets the C++ type of `this` in the member function `f`. + * The result is a glvalue if `isGLValue` is true, and + * a prvalue if `isGLValue` is false. + */ +bindingset[isGLValue] +private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) { + result.hasType(f.getTypeOfThis(), isGLValue) +} + +/** + * Gets the C++ type of the instruction `i`. + * + * This is equivalent to `i.getResultLanguageType()` with the exception + * of instructions that directly references a `this` IRVariable. In this + * case, `i.getResultLanguageType()` gives an unknown type, whereas the + * predicate gives the expected type (i.e., a potentially cv-qualified + * type `A*` where `A` is the declaring type of the member function that + * contains `i`). + */ +cached +CppType getResultLanguageType(Instruction i) { + if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable + then + if i.isGLValue() + then result = getThisType(i.getEnclosingFunction(), true) + else result = getThisType(i.getEnclosingFunction(), false) + else result = i.getResultLanguageType() +} + +/** + * Gets the C++ type of the operand `operand`. + * This is equivalent to the type of the operand's defining instruction. + * + * See `getResultLanguageType` for a description of this behavior. + */ +CppType getLanguageType(Operand operand) { result = getResultLanguageType(operand.getDef()) } + +/** + * Gets the maximum number of indirections a glvalue of type `type` can have. + * For example: + * - If `type = int`, the result is 1 + * - If `type = MyStruct`, the result is 1 + * - If `type = char*`, the result is 2 + */ +int getMaxIndirectionsForType(Type type) { + result = countIndirectionsForCppType(getTypeForGLValue(type)) +} + +/** + * Gets the maximum number of indirections a value of type `type` can have. + * + * Note that this predicate is intended to be called on unspecified types + * (i.e., `countIndirections(e.getUnspecifiedType())`). + */ +private int countIndirections(Type t) { + result = + 1 + + countIndirections([t.(Cpp::PointerType).getBaseType(), t.(Cpp::ReferenceType).getBaseType()]) + or + not t instanceof Cpp::PointerType and + not t instanceof Cpp::ReferenceType and + result = 0 +} + +/** + * Gets the maximum number of indirections a value of C++ + * type `langType` can have. + */ +int countIndirectionsForCppType(LanguageType langType) { + exists(Type type | langType.hasType(type, true) | + result = 1 + countIndirections(type.getUnspecifiedType()) + ) + or + exists(Type type | langType.hasType(type, false) | + result = countIndirections(type.getUnspecifiedType()) + ) +} + +/** + * A `CallInstruction` that calls an allocation function such + * as `malloc` or `operator new`. + */ +class AllocationInstruction extends CallInstruction { + AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction } +} + +/** + * Holds if `i` is a base instruction that starts a sequence of uses + * of some variable that SSA can handle. + * + * This is either when `i` is a `VariableAddressInstruction` or when + * `i` is a fresh allocation produced by an `AllocationInstruction`. + */ +private predicate isSourceVariableBase(Instruction i) { + i instanceof VariableAddressInstruction or i instanceof AllocationInstruction +} + +/** + * Holds if the value pointed to by `operand` can potentially be + * modified be the caller. + */ +predicate isModifiableByCall(ArgumentOperand operand) { + exists(CallInstruction call, int index, CppType type | + type = getLanguageType(operand) and + call.getArgumentOperand(index) = operand and + if index = -1 + then not call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction + else not SideEffects::isConstPointerLike(any(Type t | type.hasType(t, _))) + ) +} + +cached +private module Cached { + /** + * Holds if `op` is a use of an SSA variable rooted at `base` with `ind` number + * of indirections. + * + * `certain` is `true` if the operand is guaranteed to read the variable, and + * `indirectionIndex` specifies the number of loads required to read the variable. + */ + cached + predicate isUse(boolean certain, Operand op, Instruction base, int ind, int indirectionIndex) { + not ignoreOperand(op) and + certain = true and + exists(LanguageType type, int m, int ind0 | + type = getLanguageType(op) and + m = countIndirectionsForCppType(type) and + isUseImpl(op, base, ind0) and + ind = ind0 + [0 .. m] and + indirectionIndex = ind - ind0 + ) + } + + /** + * Holds if `operand` is a use of an SSA variable rooted at `base`, and the + * path from `base` to `operand` passes through `ind` load-like instructions. + */ + private predicate isUseImpl(Operand operand, Instruction base, int ind) { + DataFlowImplCommon::forceCachingInSameStage() and + ind = 0 and + operand.getDef() = base and + isSourceVariableBase(base) + or + exists(Operand mid, Instruction instr | + isUseImpl(mid, base, ind) and + instr = operand.getDef() and + conversionFlow(mid, instr, false) + ) + or + exists(int ind0 | + isUseImpl(operand.getDef().(LoadInstruction).getSourceAddressOperand(), base, ind0) + or + isUseImpl(operand.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0) + | + ind0 = ind - 1 + ) + } + + /** + * Holds if `address` is an address of an SSA variable rooted at `base`, + * and `instr` is a definition of the SSA variable with `ind` number of indirections. + * + * `certain` is `true` if `instr` is guaranteed to write to the variable, and + * `indirectionIndex` specifies the number of loads required to read the variable + * after the write operation. + */ + cached + predicate isDef( + boolean certain, Instruction instr, Operand address, Instruction base, int ind, + int indirectionIndex + ) { + certain = true and + exists(int ind0, CppType type, int m | + address = + [ + instr.(StoreInstruction).getDestinationAddressOperand(), + instr.(InitializeParameterInstruction).getAnOperand(), + instr.(InitializeDynamicAllocationInstruction).getAllocationAddressOperand(), + instr.(UninitializedInstruction).getAnOperand() + ] + | + isDefImpl(address, base, ind0) and + type = getLanguageType(address) and + m = countIndirectionsForCppType(type) and + ind = ind0 + [1 .. m] and + indirectionIndex = ind - (ind0 + 1) + ) + } + + /** + * Holds if `address` is a use of an SSA variable rooted at `base`, and the + * path from `base` to `address` passes through `ind` load-like instructions. + * + * Note: Unlike `isUseImpl`, this predicate recurses through pointer-arithmetic + * instructions. + */ + private predicate isDefImpl(Operand address, Instruction base, int ind) { + DataFlowImplCommon::forceCachingInSameStage() and + ind = 0 and + address.getDef() = base and + isSourceVariableBase(base) + or + exists(Operand mid, Instruction instr | + isDefImpl(mid, base, ind) and + instr = address.getDef() and + conversionFlow(mid, instr, _) + ) + or + exists(int ind0 | + isDefImpl(address.getDef().(LoadInstruction).getSourceAddressOperand(), base, ind0) + or + isDefImpl(address.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0) + | + ind0 = ind - 1 + ) + } +} + +import Cached + +/** + * Inputs to the shared SSA library's parameterized module that is shared + * between the SSA pruning stage, and the final SSA stage. + */ +module InputSigCommon { + class BasicBlock = IRBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock extends IRBlock { + ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction } + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll new file mode 100644 index 00000000000..1ab232923bf --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -0,0 +1,208 @@ +private import semmle.code.cpp.ir.IR +private import experimental.semmle.code.cpp.ir.dataflow.DataFlow +private import ModelUtil +private import semmle.code.cpp.models.interfaces.DataFlow +private import semmle.code.cpp.models.interfaces.SideEffect +private import DataFlowUtil +private import DataFlowPrivate +private import semmle.code.cpp.models.Models + +/** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ +predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + DataFlow::localFlowStep(nodeFrom, nodeTo) + or + localAdditionalTaintStep(nodeFrom, nodeTo) +} + +/** + * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding + * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent + * different objects. + */ +cached +predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + modeledTaintStep(nodeFrom, nodeTo) + or + // Flow from `op` to `*op`. + exists(Operand operand, int indirectionIndex | + nodeHasOperand(nodeFrom, operand, indirectionIndex) and + nodeHasOperand(nodeTo, operand, indirectionIndex - 1) + ) + or + // Flow from `instr` to `*instr`. + exists(Instruction instr, int indirectionIndex | + nodeHasInstruction(nodeFrom, instr, indirectionIndex) and + nodeHasInstruction(nodeTo, instr, indirectionIndex - 1) + ) + or + // Flow from (the indirection of) an operand of a pointer arithmetic instruction to the + // indirection of the pointer arithmetic instruction. This provides flow from `source` + // in `x[source]` to the result of the associated load instruction. + exists(PointerArithmeticInstruction pai, int indirectionIndex | + nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and + hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1) + ) +} + +/** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ +private predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { + // Taint can flow through expressions that alter the value but preserve + // more than one bit of it _or_ expressions that follow data through + // pointer indirections. + instrTo.getAnOperand() = opFrom and + ( + instrTo instanceof ArithmeticInstruction + or + instrTo instanceof BitwiseInstruction + or + instrTo instanceof PointerArithmeticInstruction + ) + or + // The `CopyInstruction` case is also present in non-taint data flow, but + // that uses `getDef` rather than `getAnyDef`. For taint, we want flow + // from a definition of `myStruct` to a `myStruct.myField` expression. + instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom + or + // Unary instructions tend to preserve enough information in practice that we + // want taint to flow through. + // The exception is `FieldAddressInstruction`. Together with the rules below for + // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction` + // could cause flow into one field to come out an unrelated field. + // This would happen across function boundaries, where the IR would not be able to + // match loads to stores. + instrTo.(UnaryInstruction).getUnaryOperand() = opFrom and + ( + not instrTo instanceof FieldAddressInstruction + or + instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union + ) +} + +/** + * Holds if taint may propagate from `source` to `sink` in zero or more local + * (intra-procedural) steps. + */ +pragma[inline] +predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } + +/** + * Holds if taint can flow from `i1` to `i2` in zero or more + * local (intra-procedural) steps. + */ +pragma[inline] +predicate localInstructionTaint(Instruction i1, Instruction i2) { + localTaint(DataFlow::instructionNode(i1), DataFlow::instructionNode(i2)) +} + +/** + * Holds if taint can flow from `e1` to `e2` in zero or more + * local (intra-procedural) steps. + */ +pragma[inline] +predicate localExprTaint(Expr e1, Expr e2) { + localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) +} + +/** + * Holds if the additional step from `src` to `sink` should be included in all + * global taint flow configurations. + */ +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. + */ +predicate defaultTaintSanitizer(DataFlow::Node node) { none() } + +/** + * Holds if taint can flow from `instrIn` to `instrOut` through a call to a + * modeled function. + */ +predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { + // Normal taint steps + exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut | + call.getStaticCallTarget() = func and + func.hasTaintFlow(modelIn, modelOut) + | + ( + nodeIn = callInput(call, modelIn) + or + exists(int n | + modelIn.isParameterDerefOrQualifierObject(n) and + if n = -1 + then nodeIn = callInput(call, any(InQualifierAddress inQualifier)) + else nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n)) + ) + ) and + nodeOut = callOutput(call, modelOut) + or + exists(int d | + nodeIn = callInput(call, modelIn, d) + or + exists(int n | + d = 1 and + modelIn.isParameterDerefOrQualifierObject(n) and + if n = -1 + then nodeIn = callInput(call, any(InQualifierAddress inQualifier)) + else nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n)) + ) + | + call.getStaticCallTarget() = func and + func.hasTaintFlow(modelIn, modelOut) and + nodeOut = callOutput(call, modelOut, d) + ) + ) + or + // Taint flow from one argument to another and data flow from an argument to a + // return value. This happens in functions like `strcat` and `memcpy`. We + // could model this flow in two separate steps, but that would add reverse + // flow from the write side-effect to the call instruction, which may not be + // desirable. + exists( + CallInstruction call, Function func, FunctionInput modelIn, OutParameterDeref modelMidOut, + int indexMid, InParameter modelMidIn, OutReturnValue modelOut + | + nodeIn = callInput(call, modelIn) and + nodeOut = callOutput(call, modelOut) and + call.getStaticCallTarget() = func and + func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and + func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and + modelMidOut.isParameterDeref(indexMid) and + modelMidIn.isParameter(indexMid) + ) + or + // Taint flow from a pointer argument to an output, when the model specifies flow from the deref + // to that output, but the deref is not modeled in the IR for the caller. + exists( + CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func, + FunctionInput modelIn, FunctionOutput modelOut + | + indirectArgument = callInput(call, modelIn) and + indirectArgument.getAddressOperand() = nodeIn.asOperand() and + call.getStaticCallTarget() = func and + ( + func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) + or + func.(TaintFunction).hasTaintFlow(modelIn, modelOut) + ) and + nodeOut = callOutput(call, modelOut) + ) +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll new file mode 100644 index 00000000000..3a89f1d170f --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll @@ -0,0 +1,314 @@ +/** + * This module defines an initial SSA pruning stage that doesn't take + * indirections into account. + */ + +private import codeql.ssa.Ssa as SsaImplCommon +private import semmle.code.cpp.ir.IR +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.cpp.models.interfaces.Allocation as Alloc +private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow +private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects +private import semmle.code.cpp.ir.internal.IRCppLanguage +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate +private import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import experimental.semmle.code.cpp.ir.dataflow.internal.SsaInternalsCommon + +private module SourceVariables { + newtype TBaseSourceVariable = + // Each IR variable gets its own source variable + TBaseIRVariable(IRVariable var) or + // Each allocation gets its own source variable + TBaseCallVariable(AllocationInstruction call) + + abstract class BaseSourceVariable extends TBaseSourceVariable { + abstract string toString(); + + abstract DataFlowType getType(); + } + + class BaseIRVariable extends BaseSourceVariable, TBaseIRVariable { + IRVariable var; + + IRVariable getIRVariable() { result = var } + + BaseIRVariable() { this = TBaseIRVariable(var) } + + override string toString() { result = var.toString() } + + override DataFlowType getType() { result = var.getIRType() } + } + + class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable { + AllocationInstruction call; + + BaseCallVariable() { this = TBaseCallVariable(call) } + + AllocationInstruction getCallInstruction() { result = call } + + override string toString() { result = call.toString() } + + override DataFlowType getType() { result = call.getResultIRType() } + } + + private newtype TSourceVariable = + TSourceIRVariable(BaseIRVariable baseVar) or + TCallVariable(AllocationInstruction call) + + abstract class SourceVariable extends TSourceVariable { + abstract string toString(); + + abstract BaseSourceVariable getBaseVariable(); + } + + class SourceIRVariable extends SourceVariable, TSourceIRVariable { + BaseIRVariable var; + + SourceIRVariable() { this = TSourceIRVariable(var) } + + IRVariable getIRVariable() { result = var.getIRVariable() } + + override BaseIRVariable getBaseVariable() { result.getIRVariable() = this.getIRVariable() } + + override string toString() { result = this.getIRVariable().toString() } + } + + class CallVariable extends SourceVariable, TCallVariable { + AllocationInstruction call; + + CallVariable() { this = TCallVariable(call) } + + AllocationInstruction getCall() { result = call } + + override BaseCallVariable getBaseVariable() { result.getCallInstruction() = call } + + override string toString() { result = "Call" } + } +} + +import SourceVariables + +private newtype TDefOrUseImpl = + TDefImpl(Operand address) { isDef(_, _, address, _, _, _) } or + TUseImpl(Operand operand) { + isUse(_, operand, _, _, _) and + not isDef(_, _, operand, _, _, _) + } + +abstract private class DefOrUseImpl extends TDefOrUseImpl { + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets the block of this definition or use. */ + abstract IRBlock getBlock(); + + /** Holds if this definition or use has index `index` in block `block`. */ + abstract predicate hasIndexInBlock(IRBlock block, int index); + + final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) { + this.hasIndexInBlock(block, index) and + sv = this.getSourceVariable() + } + + /** Gets the location of this element. */ + abstract Cpp::Location getLocation(); + + abstract Instruction getBase(); + + final BaseSourceVariable getBaseSourceVariable() { + exists(IRVariable var | + result.(BaseIRVariable).getIRVariable() = var and + instructionHasIRVariable(this.getBase(), var) + ) + or + result.(BaseCallVariable).getCallInstruction() = this.getBase() + } + + /** Gets the variable that is defined or used. */ + final SourceVariable getSourceVariable() { + exists(BaseSourceVariable v | + sourceVariableHasBaseAndIndex(result, v) and + defOrUseHasSourceVariable(this, v) + ) + } +} + +pragma[noinline] +private predicate instructionHasIRVariable(VariableAddressInstruction vai, IRVariable var) { + vai.getIRVariable() = var +} + +private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv) { + defHasSourceVariable(defOrUse, bv) + or + useHasSourceVariable(defOrUse, bv) +} + +pragma[noinline] +private predicate defHasSourceVariable(DefImpl def, BaseSourceVariable bv) { + bv = def.getBaseSourceVariable() +} + +pragma[noinline] +private predicate useHasSourceVariable(UseImpl use, BaseSourceVariable bv) { + bv = use.getBaseSourceVariable() +} + +pragma[noinline] +private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVariable bv) { + v.getBaseVariable() = bv +} + +class DefImpl extends DefOrUseImpl, TDefImpl { + Operand address; + + DefImpl() { this = TDefImpl(address) } + + override Instruction getBase() { isDef(_, _, address, result, _, _) } + + Operand getAddressOperand() { result = address } + + Instruction getDefiningInstruction() { isDef(_, result, address, _, _, _) } + + override string toString() { result = address.toString() } + + override IRBlock getBlock() { result = this.getDefiningInstruction().getBlock() } + + override Cpp::Location getLocation() { result = this.getDefiningInstruction().getLocation() } + + final override predicate hasIndexInBlock(IRBlock block, int index) { + this.getDefiningInstruction() = block.getInstruction(index) + } + + predicate isCertain() { isDef(true, _, address, _, _, _) } +} + +class UseImpl extends DefOrUseImpl, TUseImpl { + Operand operand; + + UseImpl() { this = TUseImpl(operand) } + + Operand getOperand() { result = operand } + + override string toString() { result = operand.toString() } + + final override predicate hasIndexInBlock(IRBlock block, int index) { + operand.getUse() = block.getInstruction(index) + } + + final override IRBlock getBlock() { result = operand.getUse().getBlock() } + + final override Cpp::Location getLocation() { result = operand.getLocation() } + + override Instruction getBase() { isUse(_, operand, result, _, _) } + + predicate isCertain() { isUse(true, operand, _, _, _) } +} + +private module SsaInput implements SsaImplCommon::InputSig { + import InputSigCommon + import SourceVariables + + /** + * Holds if the `i`'th write in block `bb` writes to the variable `v`. + * `certain` is `true` if the write is guaranteed to overwrite the entire variable. + */ + predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) { + DataFlowImplCommon::forceCachingInSameStage() and + exists(DefImpl def | def.hasIndexInBlock(bb, i, v) | + if def.isCertain() then certain = true else certain = false + ) + } + + /** + * Holds if the `i`'th read in block `bb` reads to the variable `v`. + * `certain` is `true` if the read is guaranteed. + */ + predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) { + exists(UseImpl use | use.hasIndexInBlock(bb, i, v) | + if use.isCertain() then certain = true else certain = false + ) + } +} + +private newtype TSsaDefOrUse = + TDefOrUse(DefOrUseImpl defOrUse) { + defOrUse instanceof UseImpl + or + // If `defOrUse` is a definition we only include it if the + // SSA library concludes that it's live after the write. + exists(Definition def, SourceVariable sv, IRBlock bb, int i | + def.definesAt(sv, bb, i) and + defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv) + ) + } or + TPhi(PhiNode phi) + +abstract private class SsaDefOrUse extends TSsaDefOrUse { + string toString() { result = "SsaDefOrUse" } + + DefOrUseImpl asDefOrUse() { none() } + + PhiNode asPhi() { none() } + + abstract Location getLocation(); +} + +class DefOrUse extends TDefOrUse, SsaDefOrUse { + DefOrUseImpl defOrUse; + + DefOrUse() { this = TDefOrUse(defOrUse) } + + final override DefOrUseImpl asDefOrUse() { result = defOrUse } + + final override Location getLocation() { result = defOrUse.getLocation() } + + final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() } +} + +class Phi extends TPhi, SsaDefOrUse { + PhiNode phi; + + Phi() { this = TPhi(phi) } + + final override PhiNode asPhi() { result = phi } + + final override Location getLocation() { result = phi.getBasicBlock().getLocation() } +} + +class UseOrPhi extends SsaDefOrUse { + UseOrPhi() { + this.asDefOrUse() instanceof UseImpl + or + this instanceof Phi + } + + final override Location getLocation() { + result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation() + } + + override string toString() { + result = this.asDefOrUse().toString() + or + this instanceof Phi and + result = "Phi" + } +} + +class Def extends DefOrUse { + override DefImpl defOrUse; + + Operand getAddressOperand() { result = defOrUse.getAddressOperand() } + + Instruction getAddress() { result = this.getAddressOperand().getDef() } + + Instruction getDefiningInstruction() { result = defOrUse.getDefiningInstruction() } + + override string toString() { result = this.asDefOrUse().toString() + " (def)" } +} + +private module SsaImpl = SsaImplCommon::Make; + +class PhiNode = SsaImpl::PhiNode; + +class Definition = SsaImpl::Definition; diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll new file mode 100644 index 00000000000..bf937b6de31 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -0,0 +1,191 @@ +/** + * Provides an implementation of global (interprocedural) taint tracking. + * This file re-exports the local (intraprocedural) taint-tracking analysis + * from `TaintTrackingParameter::Public` and adds a global analysis, mainly + * exposed through the `Configuration` class. For some languages, this file + * exists in several identical copies, allowing queries to use multiple + * `Configuration` classes that depend on each other without introducing + * mutual recursion among those configurations. + */ + +import TaintTrackingParameter::Public +private import TaintTrackingParameter::Private + +/** + * A configuration of interprocedural taint tracking analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the taint tracking library must define its own unique extension of + * this abstract class. + * + * A taint-tracking configuration is a special data flow configuration + * (`DataFlow::Configuration`) that allows for flow through nodes that do not + * necessarily preserve values but are still relevant from a taint tracking + * perspective. (For example, string concatenation, where one of the operands + * is tainted.) + * + * To create a configuration, extend this class with a subclass whose + * characteristic predicate is a unique singleton string. For example, write + * + * ```ql + * class MyAnalysisConfiguration extends TaintTracking::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isSanitizer`. + * // Optionally override `isSanitizerIn`. + * // Optionally override `isSanitizerOut`. + * // Optionally override `isSanitizerGuard`. + * // Optionally override `isAdditionalTaintStep`. + * } + * ``` + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but it is unsupported to depend on + * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the + * overridden predicates that define sources, sinks, or additional steps. + * Instead, the dependency should go to a `TaintTracking2::Configuration` or a + * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. + */ +abstract class Configuration extends DataFlow::Configuration { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant taint source. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source) { none() } + + /** + * Holds if `source` is a relevant taint source with the given initial + * `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() } + + /** + * Holds if `sink` is a relevant taint sink + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink) { none() } + + /** + * Holds if `sink` is a relevant taint sink accepting `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() } + + /** Holds if the node `node` is a taint sanitizer. */ + predicate isSanitizer(DataFlow::Node node) { none() } + + final override predicate isBarrier(DataFlow::Node node) { + this.isSanitizer(node) or + defaultTaintSanitizer(node) + } + + /** + * Holds if the node `node` is a taint sanitizer when the flow state is + * `state`. + */ + predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() } + + final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { + this.isSanitizer(node, state) + } + + /** Holds if taint propagation into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } + + /** Holds if taint propagation out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited + * when the flow state is `state`. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { + none() + } + + deprecated final override predicate isBarrierGuard( + DataFlow::BarrierGuard guard, DataFlow::FlowState state + ) { + this.isSanitizerGuard(guard, state) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + */ + predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + + final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + this.isAdditionalTaintStep(node1, node2) or + defaultAdditionalTaintStep(node1, node2) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalTaintStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + none() + } + + final override predicate isAdditionalFlowStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + this.isAdditionalTaintStep(node1, state1, node2, state2) + } + + override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and + defaultImplicitTaintRead(node, c) + } + + /** + * Holds if taint may flow from `source` to `sink` for this configuration. + */ + // overridden to provide taint-tracking specific qldoc + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + super.hasFlow(source, sink) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll new file mode 100644 index 00000000000..07185a4ad57 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll @@ -0,0 +1,5 @@ +import experimental.semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public + +module Private { + import experimental.semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll new file mode 100644 index 00000000000..bf937b6de31 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -0,0 +1,191 @@ +/** + * Provides an implementation of global (interprocedural) taint tracking. + * This file re-exports the local (intraprocedural) taint-tracking analysis + * from `TaintTrackingParameter::Public` and adds a global analysis, mainly + * exposed through the `Configuration` class. For some languages, this file + * exists in several identical copies, allowing queries to use multiple + * `Configuration` classes that depend on each other without introducing + * mutual recursion among those configurations. + */ + +import TaintTrackingParameter::Public +private import TaintTrackingParameter::Private + +/** + * A configuration of interprocedural taint tracking analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the taint tracking library must define its own unique extension of + * this abstract class. + * + * A taint-tracking configuration is a special data flow configuration + * (`DataFlow::Configuration`) that allows for flow through nodes that do not + * necessarily preserve values but are still relevant from a taint tracking + * perspective. (For example, string concatenation, where one of the operands + * is tainted.) + * + * To create a configuration, extend this class with a subclass whose + * characteristic predicate is a unique singleton string. For example, write + * + * ```ql + * class MyAnalysisConfiguration extends TaintTracking::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isSanitizer`. + * // Optionally override `isSanitizerIn`. + * // Optionally override `isSanitizerOut`. + * // Optionally override `isSanitizerGuard`. + * // Optionally override `isAdditionalTaintStep`. + * } + * ``` + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but it is unsupported to depend on + * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the + * overridden predicates that define sources, sinks, or additional steps. + * Instead, the dependency should go to a `TaintTracking2::Configuration` or a + * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. + */ +abstract class Configuration extends DataFlow::Configuration { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant taint source. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source) { none() } + + /** + * Holds if `source` is a relevant taint source with the given initial + * `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() } + + /** + * Holds if `sink` is a relevant taint sink + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink) { none() } + + /** + * Holds if `sink` is a relevant taint sink accepting `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() } + + /** Holds if the node `node` is a taint sanitizer. */ + predicate isSanitizer(DataFlow::Node node) { none() } + + final override predicate isBarrier(DataFlow::Node node) { + this.isSanitizer(node) or + defaultTaintSanitizer(node) + } + + /** + * Holds if the node `node` is a taint sanitizer when the flow state is + * `state`. + */ + predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() } + + final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { + this.isSanitizer(node, state) + } + + /** Holds if taint propagation into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } + + /** Holds if taint propagation out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited + * when the flow state is `state`. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { + none() + } + + deprecated final override predicate isBarrierGuard( + DataFlow::BarrierGuard guard, DataFlow::FlowState state + ) { + this.isSanitizerGuard(guard, state) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + */ + predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + + final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + this.isAdditionalTaintStep(node1, node2) or + defaultAdditionalTaintStep(node1, node2) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalTaintStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + none() + } + + final override predicate isAdditionalFlowStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + this.isAdditionalTaintStep(node1, state1, node2, state2) + } + + override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and + defaultImplicitTaintRead(node, c) + } + + /** + * Holds if taint may flow from `source` to `sink` for this configuration. + */ + // overridden to provide taint-tracking specific qldoc + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + super.hasFlow(source, sink) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll new file mode 100644 index 00000000000..7d545fe5d04 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll @@ -0,0 +1,5 @@ +import experimental.semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public + +module Private { + import experimental.semmle.code.cpp.ir.dataflow.DataFlow2::DataFlow2 as DataFlow +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll new file mode 100644 index 00000000000..bf937b6de31 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -0,0 +1,191 @@ +/** + * Provides an implementation of global (interprocedural) taint tracking. + * This file re-exports the local (intraprocedural) taint-tracking analysis + * from `TaintTrackingParameter::Public` and adds a global analysis, mainly + * exposed through the `Configuration` class. For some languages, this file + * exists in several identical copies, allowing queries to use multiple + * `Configuration` classes that depend on each other without introducing + * mutual recursion among those configurations. + */ + +import TaintTrackingParameter::Public +private import TaintTrackingParameter::Private + +/** + * A configuration of interprocedural taint tracking analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the taint tracking library must define its own unique extension of + * this abstract class. + * + * A taint-tracking configuration is a special data flow configuration + * (`DataFlow::Configuration`) that allows for flow through nodes that do not + * necessarily preserve values but are still relevant from a taint tracking + * perspective. (For example, string concatenation, where one of the operands + * is tainted.) + * + * To create a configuration, extend this class with a subclass whose + * characteristic predicate is a unique singleton string. For example, write + * + * ```ql + * class MyAnalysisConfiguration extends TaintTracking::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isSanitizer`. + * // Optionally override `isSanitizerIn`. + * // Optionally override `isSanitizerOut`. + * // Optionally override `isSanitizerGuard`. + * // Optionally override `isAdditionalTaintStep`. + * } + * ``` + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but it is unsupported to depend on + * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the + * overridden predicates that define sources, sinks, or additional steps. + * Instead, the dependency should go to a `TaintTracking2::Configuration` or a + * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. + */ +abstract class Configuration extends DataFlow::Configuration { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant taint source. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source) { none() } + + /** + * Holds if `source` is a relevant taint source with the given initial + * `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() } + + /** + * Holds if `sink` is a relevant taint sink + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink) { none() } + + /** + * Holds if `sink` is a relevant taint sink accepting `state`. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() } + + /** Holds if the node `node` is a taint sanitizer. */ + predicate isSanitizer(DataFlow::Node node) { none() } + + final override predicate isBarrier(DataFlow::Node node) { + this.isSanitizer(node) or + defaultTaintSanitizer(node) + } + + /** + * Holds if the node `node` is a taint sanitizer when the flow state is + * `state`. + */ + predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() } + + final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { + this.isSanitizer(node, state) + } + + /** Holds if taint propagation into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } + + /** Holds if taint propagation out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } + + /** + * DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead. + * + * Holds if taint propagation through nodes guarded by `guard` is prohibited + * when the flow state is `state`. + */ + deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { + none() + } + + deprecated final override predicate isBarrierGuard( + DataFlow::BarrierGuard guard, DataFlow::FlowState state + ) { + this.isSanitizerGuard(guard, state) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + */ + predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + + final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + this.isAdditionalTaintStep(node1, node2) or + defaultAdditionalTaintStep(node1, node2) + } + + /** + * Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps. + * This step is only applicable in `state1` and updates the flow state to `state2`. + */ + predicate isAdditionalTaintStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + none() + } + + final override predicate isAdditionalFlowStep( + DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, + DataFlow::FlowState state2 + ) { + this.isAdditionalTaintStep(node1, state1, node2, state2) + } + + override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and + defaultImplicitTaintRead(node, c) + } + + /** + * Holds if taint may flow from `source` to `sink` for this configuration. + */ + // overridden to provide taint-tracking specific qldoc + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + super.hasFlow(source, sink) + } +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll new file mode 100644 index 00000000000..3e69abcf4a7 --- /dev/null +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll @@ -0,0 +1,5 @@ +import experimental.semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public + +module Private { + import experimental.semmle.code.cpp.ir.dataflow.DataFlow3::DataFlow3 as DataFlow +} diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/Bound.qll index bdd0e39f9b7..abff447ca87 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/Bound.qll @@ -28,6 +28,10 @@ private newtype TBound = i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction or i.getAUse() instanceof ArgumentOperand + or + i instanceof PointerArithmeticInstruction + or + i.getAUse() instanceof AddressOperand ) } @@ -73,7 +77,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber { this = TBoundValueNumber(valueNumber(result)) and delta = 0 } - override string toString() { result = vn.getExampleInstruction().toString() } + override string toString() { result = "ValueNumberBound" } override Location getLocation() { result = vn.getLocation() } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExpr.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExpr.qll index 8aeb15cab12..2ea958931da 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExpr.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExpr.qll @@ -178,11 +178,11 @@ class SemRelationalExpr extends SemBinaryExpr { } class SemAddExpr extends SemBinaryExpr { - SemAddExpr() { opcode instanceof Opcode::Add } + SemAddExpr() { opcode instanceof Opcode::Add or opcode instanceof Opcode::PointerAdd } } class SemSubExpr extends SemBinaryExpr { - SemSubExpr() { opcode instanceof Opcode::Sub } + SemSubExpr() { opcode instanceof Opcode::Sub or opcode instanceof Opcode::PointerSub } } class SemMulExpr extends SemBinaryExpr { diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll index 3ed2c49e5c0..dc178f77547 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll @@ -112,12 +112,11 @@ module SemanticExprConfig { predicate hasDominanceInformation(BasicBlock block) { any() } - int getBasicBlockUniqueId(BasicBlock block) { - // REVIEW: `getDisplayIndex()` is not intended for use in real queries, but for now it's the - // best we can do because `equivalentRelation` won't accept a predicate whose parameters are IPA - // types. - result = block.getDisplayIndex() - } + private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y } + + private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y) + + int getBasicBlockUniqueId(BasicBlock block) { idOf(block.getFirstInstruction().getAst(), result) } newtype TSsaVariable = TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or @@ -162,7 +161,7 @@ module SemanticExprConfig { predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction } SsaVariable getAPhiInput(SsaVariable v) { - exists(IR::PhiInstruction instr | + exists(IR::PhiInstruction instr | v.asInstruction() = instr | result.asInstruction() = instr.getAnInput() or result.asOperand() = instr.getAnInputOperand() @@ -267,17 +266,7 @@ module SemanticExprConfig { ValueNumberBound() { bound = this } - override string toString() { - result = - min(SsaVariable v | - v.asInstruction() = bound.getValueNumber().getAnInstruction() - | - v - order by - v.asInstruction().getBlock().getDisplayIndex(), - v.asInstruction().getDisplayIndexInBlock() - ).toString() - } + override string toString() { result = bound.toString() } } predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticOpcode.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticOpcode.qll index 304d299dfba..bb56da71f73 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticOpcode.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticOpcode.qll @@ -65,10 +65,18 @@ module Opcode { override string toString() { result = "Add" } } + class PointerAdd extends Opcode, TPointerAdd { + override string toString() { result = "PointerAdd" } + } + class Sub extends Opcode, TSub { override string toString() { result = "Sub" } } + class PointerSub extends Opcode, TPointerSub { + override string toString() { result = "PointerSub" } + } + class Mul extends Opcode, TMul { override string toString() { result = "Mul" } } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll index 4f8462705b1..4953b994c8e 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll @@ -223,7 +223,9 @@ private SemGuard boundFlowCond( else resultIsStrict = testIsTrue.booleanNot() ) and ( - if getTrackedTypeForSsaVariable(v) instanceof SemIntegerType + if + getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or + getTrackedTypeForSsaVariable(v) instanceof SemAddressType then upper = true and strengthen = -1 or @@ -542,12 +544,32 @@ private predicate unequalIntegralSsa( ) { exists(SemExpr e, int d1, int d2 | unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and - bounded(e, b, d2, true, _, _, _) and - bounded(e, b, d2, false, _, _, _) and + boundedUpper(e, b, d1) and + boundedLower(e, b, d2) and delta = d2 + d1 ) } +/** + * Holds if `b + delta` is an upper bound for `e`. + * + * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`. + */ +pragma[nomagic] +private predicate boundedUpper(SemExpr e, SemBound b, int delta) { + bounded(e, b, delta, true, _, _, _) +} + +/** + * Holds if `b + delta` is a lower bound for `e`. + * + * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`. + */ +pragma[nomagic] +private predicate boundedLower(SemExpr e, SemBound b, int delta) { + bounded(e, b, delta, false, _, _, _) +} + /** Weakens a delta to lie in the range `[-1..1]`. */ bindingset[delta, upper] private int weakenDelta(boolean upper, int delta) { diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll index 6015c33c035..10944b55fbc 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll @@ -204,6 +204,7 @@ private class BinarySignExpr extends FlowSignExpr { } } +pragma[nomagic] private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) { binary.getLeftOperand() = left and binary.getRightOperand() = right } diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 4d96d9635ed..432fe263feb 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -5,3 +5,5 @@ dbscheme: semmlecode.cpp.dbscheme extractor: cpp library: true upgrades: upgrades +dependencies: + codeql/ssa: 0.0.1 diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll index a91cedb9a0b..f139f67c70a 100644 --- a/cpp/ql/lib/semmle/code/cpp/Class.qll +++ b/cpp/ql/lib/semmle/code/cpp/Class.qll @@ -404,7 +404,10 @@ class Class extends UserType { * compiled for. For this reason, the `is_pod_class` predicate is * generated by the extractor. */ - predicate isPOD() { is_pod_class(underlyingElement(this)) } + predicate isPod() { is_pod_class(underlyingElement(this)) } + + /** DEPRECATED: Alias for isPod */ + deprecated predicate isPOD() { this.isPod() } /** * Holds if this class, struct or union is a standard-layout class diff --git a/cpp/ql/lib/semmle/code/cpp/PODType03.qll b/cpp/ql/lib/semmle/code/cpp/PODType03.qll index 88c9a1203aa..4d6e5262213 100644 --- a/cpp/ql/lib/semmle/code/cpp/PODType03.qll +++ b/cpp/ql/lib/semmle/code/cpp/PODType03.qll @@ -79,17 +79,17 @@ predicate isAggregateType03(Type t) { * user-defined copy assignment operator and no user-defined destructor. * A POD class is a class that is either a POD-struct or a POD-union. */ -predicate isPODClass03(Class c) { +predicate isPodClass03(Class c) { isAggregateClass03(c) and not exists(Variable v | v.getDeclaringType() = c and not v.isStatic() | - not isPODType03(v.getType()) + not isPodType03(v.getType()) or exists(ArrayType at | at = v.getType() and - not isPODType03(at.getBaseType()) + not isPodType03(at.getBaseType()) ) or v.getType() instanceof ReferenceType @@ -104,6 +104,9 @@ predicate isPODClass03(Class c) { ) } +/** DEPRECATED: Alias for isPodClass03 */ +deprecated predicate isPODClass03 = isPodClass03/1; + /** * Holds if `t` is a POD type, according to the rules specified in * C++03 3.9(10): @@ -112,14 +115,17 @@ predicate isPODClass03(Class c) { * such types and cv-qualified versions of these types (3.9.3) are * collectively called POD types. */ -predicate isPODType03(Type t) { +predicate isPodType03(Type t) { exists(Type ut | ut = t.getUnderlyingType() | isScalarType03(ut) or - isPODClass03(ut) + isPodClass03(ut) or - exists(ArrayType at | at = ut and isPODType03(at.getBaseType())) + exists(ArrayType at | at = ut and isPodType03(at.getBaseType())) or - isPODType03(ut.(SpecifiedType).getUnspecifiedType()) + isPodType03(ut.(SpecifiedType).getUnspecifiedType()) ) } + +/** DEPRECATED: Alias for isPodType03 */ +deprecated predicate isPODType03 = isPodType03/1; diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll b/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll index ec95b29177b..e7169d6917f 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll @@ -238,7 +238,7 @@ predicate dependsOnTransitive(DependsSource src, Element dest) { /** * A dependency that targets a TypeDeclarationEntry. */ -private predicate dependsOnTDE(Element src, Type t, TypeDeclarationEntry dest) { +private predicate dependsOnTde(Element src, Type t, TypeDeclarationEntry dest) { dependsOnTransitive(src, t) and getDeclarationEntries(t, dest) } @@ -247,8 +247,8 @@ private predicate dependsOnTDE(Element src, Type t, TypeDeclarationEntry dest) { * A dependency that targets a visible TypeDeclarationEntry. */ pragma[noopt] -private predicate dependsOnVisibleTDE(Element src, Type t, TypeDeclarationEntry dest) { - dependsOnTDE(src, t, dest) and +private predicate dependsOnVisibleTde(Element src, Type t, TypeDeclarationEntry dest) { + dependsOnTde(src, t, dest) and exists(File g | g = dest.getFile() | exists(File f | f = src.getFile() | f.getAnIncludedFile*() = g) ) @@ -260,8 +260,8 @@ private predicate dependsOnVisibleTDE(Element src, Type t, TypeDeclarationEntry private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest) { exists(Type t | // dependency from a Type use -> unique visible TDE - dependsOnVisibleTDE(src, t, dest) and - strictcount(TypeDeclarationEntry alt | dependsOnVisibleTDE(src, t, alt)) = 1 + dependsOnVisibleTde(src, t, dest) and + strictcount(TypeDeclarationEntry alt | dependsOnVisibleTde(src, t, alt)) = 1 ) or exists(TypedefType mid | diff --git a/cpp/ql/lib/semmle/code/cpp/commons/NULL.qll b/cpp/ql/lib/semmle/code/cpp/commons/NULL.qll index fa6008f1379..54981548245 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/NULL.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/NULL.qll @@ -1,11 +1,14 @@ import semmle.code.cpp.Macro /** A macro defining NULL. */ -class NULLMacro extends Macro { - NULLMacro() { this.getHead() = "NULL" } +class NullMacro extends Macro { + NullMacro() { this.getHead() = "NULL" } } +/** DEPRECATED: Alias for NullMacro */ +deprecated class NULLMacro = NullMacro; + /** A use of the NULL macro. */ class NULL extends Literal { - NULL() { exists(NULLMacro nm | this = nm.getAnInvocation().getAnExpandedElement()) } + NULL() { exists(NullMacro nm | this = nm.getAnInvocation().getAnExpandedElement()) } } diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll b/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll index 58d980318d9..0d51c948170 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll @@ -143,6 +143,28 @@ class ScanfFunctionCall extends FunctionCall { * (rather than a `char*`). */ predicate isWideCharDefault() { this.getScanfFunction().isWideCharDefault() } + + /** + * Gets the output argument at position `n` in the vararg list of this call. + * + * The range of `n` is from `0` to `this.getNumberOfOutputArguments() - 1`. + */ + Expr getOutputArgument(int n) { + result = this.getArgument(this.getTarget().getNumberOfParameters() + n) and + n >= 0 + } + + /** + * Gets an output argument given to this call in vararg position. + */ + Expr getAnOutputArgument() { result = this.getOutputArgument(_) } + + /** + * Gets the number of output arguments present in this call. + */ + int getNumberOfOutputArguments() { + result = this.getNumberOfArguments() - this.getTarget().getNumberOfParameters() + } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll index 34b2ef5aaf9..ee76e9aa671 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -474,7 +474,7 @@ module FlowVar_internal { } /** Type-specialized version of `getEnclosingElement`. */ - private ControlFlowNode getCFNParent(ControlFlowNode node) { result = node.getEnclosingElement() } + private ControlFlowNode getCfnParent(ControlFlowNode node) { result = node.getEnclosingElement() } /** * A for-loop or while-loop whose condition is always true upon entry but not @@ -526,7 +526,7 @@ module FlowVar_internal { } private predicate bbInLoopCondition(BasicBlock bb) { - getCFNParent*(bb.getANode()) = this.(Loop).getCondition() + getCfnParent*(bb.getANode()) = this.(Loop).getCondition() } private predicate bbInLoop(BasicBlock bb) { diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll index 979c9c03940..f5ead5b6f5f 100644 --- a/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -1040,6 +1040,494 @@ class BuiltInOperationHasUniqueObjectRepresentations extends BuiltInOperation, override string getAPrimaryQlClass() { result = "BuiltInOperationHasUniqueObjectRepresentations" } } +/** + * A C++ `__is_same` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if two types are the same. + * ``` + * template + * struct is_same + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsSame extends BuiltInOperation, @issame { + override string toString() { result = "__is_same" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSame" } +} + +/** + * A C++ `__is_function` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a function type. + * ``` + * template + * struct is_function + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsFunction extends BuiltInOperation, @isfunction { + override string toString() { result = "__is_function" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFunction" } +} + +/** + * A C++ `__is_layout_compatible` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if two types are layout-compatible. + * ``` + * template + * struct is_layout_compatible + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsLayoutCompatible extends BuiltInOperation, @islayoutcompatible { + override string toString() { result = "__is_layout_compatible" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsLayoutCompatible" } +} + +/** + * A C++ `__is_pointer_interconvertible_base_of` built-in operation (used + * by some implementations of the `` header). + * + * Returns `true` if the second type is pointer-interconvertible with the first type. + * ``` + * template + * struct is_pointer_interconvertible_base_of_v + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsPointerInterconvertibleBaseOf extends BuiltInOperation, + @ispointerinterconvertiblebaseof { + override string toString() { result = "__is_pointer_interconvertible_base_of" } + + override string getAPrimaryQlClass() { + result = "BuiltInOperationIsPointerInterconvertibleBaseOf" + } +} + +/** + * A C++ `__is_array` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is an array type. + * ``` + * template + * struct is_array + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsArray extends BuiltInOperation, @isarray { + override string toString() { result = "__is_array" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsArray" } +} + +/** + * A C++ `__array_rank` built-in operation (used by some implementations of the + * `` header). + * + * If known, returns the number of dimentsions of an arrary type. + * ``` + * template + * struct rank + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationArrayRank extends BuiltInOperation, @arrayrank { + override string toString() { result = "__array_rank" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationArrayRank" } +} + +/** + * A C++ `__array_extent` built-in operation (used by some implementations of the + * `` header). + * + * If known, returns the number of elements of an arrary type in the specified + * dimension. + * ``` + * template + * struct extent + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationArrayExtent extends BuiltInOperation, @arrayextent { + override string toString() { result = "__array_extent" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationArrayExtent" } +} + +/** + * A C++ `__is_arithmetic` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is an arithmetic type. + * ``` + * template + * struct is_arithmetic + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsArithmetic extends BuiltInOperation, @isarithmetic { + override string toString() { result = "__is_arithmetic" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsArithmetic" } +} + +/** + * A C++ `__is_complete_type` built-in operation. + * + * Returns `true` if a type is a complete type. Note that this built-in operation + * can return different values for the same type at different points in a program. + * ``` + * class S; + * bool b = __complete_type(S); + * ``` + */ +class BuiltInOperationIsCompleteType extends BuiltInOperation, @iscompletetype { + override string toString() { result = "__is_complete_type" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsCompleteType" } +} + +/** + * A C++ `__is_compound` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a compound type. + * ``` + * template + * struct is_compound + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsCompound extends BuiltInOperation, @iscompound { + override string toString() { result = "__is_compound" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsCompound" } +} + +/** + * A C++ `__is_const` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a const-qualified type. + * ``` + * template + * struct is_const + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsConst extends BuiltInOperation, @isconst { + override string toString() { result = "__is_const" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConst" } +} + +/** + * A C++ `__is_floating_point` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is a floating point type. + * ``` + * template + * struct is_floating_point + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsFloatingPoint extends BuiltInOperation, @isfloatingpoint { + override string toString() { result = "__is_floating_point" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFloatingPoint" } +} + +/** + * A C++ `__is_fundamental` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a fundamental C++ type. + * ``` + * template + * struct is_fundamental + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsFundamental extends BuiltInOperation, @isfundamental { + override string toString() { result = "__is_fundamental" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFundamental" } +} + +/** + * A C++ `__is_integral` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is an integral type. + * ``` + * template + * struct is_integral + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsIntegral extends BuiltInOperation, @isintegral { + override string toString() { result = "__is_integral" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsIntegral" } +} + +/** + * A C++ `__is_lvalue_reference` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an lvalue reference type. + * ``` + * template + * struct is_lvalue_reference + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsLvalueReference extends BuiltInOperation, @islvaluereference { + override string toString() { result = "__is_lvalue_reference" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsLvalueReference" } +} + +/** + * A C++ `__is_member_function_pointer` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an non-static member function pointer type. + * ``` + * template + * struct is_member_function_pointer + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsMemberFunctionPointer extends BuiltInOperation, @ismemberfunctionpointer { + override string toString() { result = "__is_member_function_pointer" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsMemberFunctionPointer" } +} + +/** + * A C++ `__is_member_object_pointer` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an non-static member object pointer type. + * ``` + * template + * struct is_member_object_pointer + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsMemberObjectPointer extends BuiltInOperation, @ismemberobjectpointer { + override string toString() { result = "__is_member_object_pointer" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsMemberObjectPointer" } +} + +/** + * A C++ `__is_member_pointer` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an non-static member object of function pointer type. + * ``` + * template + * struct is_member_pointer + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsMemberPointer extends BuiltInOperation, @ismemberpointer { + override string toString() { result = "__is_member_pointer" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsMemberPointer" } +} + +/** + * A C++ `__is_object` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an object type. + * ``` + * template + * struct is_object + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsObject extends BuiltInOperation, @isobject { + override string toString() { result = "__is_object" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsObject" } +} + +/** + * A C++ `__is_pointer` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is a pointer to an object or function type. + * ``` + * template + * struct is_pointer + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsPointer extends BuiltInOperation, @ispointer { + override string toString() { result = "__is_pointer" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPointer" } +} + +/** + * A C++ `__is_reference` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an lvalue or rvalue reference type. + * ``` + * template + * struct is_reference + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsReference extends BuiltInOperation, @isreference { + override string toString() { result = "__is_reference" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsReference" } +} + +/** + * A C++ `__is_rvalue_reference` built-in operation (used by some implementations + * of the `` header). + * + * Returns `true` if a type is an rvalue reference type. + * ``` + * template + * struct is_rvalue_reference + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsRvalueReference extends BuiltInOperation, @isrvaluereference { + override string toString() { result = "__is_rvalue_reference" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRvalueReference" } +} + +/** + * A C++ `__is_scalar` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a scalar type. + * ``` + * template + * struct is_scalar + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsScalar extends BuiltInOperation, @isscalar { + override string toString() { result = "__is_scalar" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsScalar" } +} + +/** + * A C++ `__is_signed` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a signed arithmetic type. + * ``` + * template + * struct is_signed + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsSigned extends BuiltInOperation, @issigned { + override string toString() { result = "__is_signed" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSigned" } +} + +/** + * A C++ `__is_unsigned` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is an unsigned arithmetic type. + * ``` + * template + * struct is_unsigned + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsUnsigned extends BuiltInOperation, @isunsigned { + override string toString() { result = "__is_unsigned" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnsigned" } +} + +/** + * A C++ `__is_void` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a void type. + * ``` + * template + * struct is_void + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsVoid extends BuiltInOperation, @isvoid { + override string toString() { result = "__is_void" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsVoid" } +} + +/** + * A C++ `__is_volatile` built-in operation (used by some implementations of the + * `` header). + * + * Returns `true` if a type is a volatile-qualified type. + * ``` + * template + * struct is_volatile + * : public integral_constant + * { }; + * ``` + */ +class BuiltInOperationIsVolatile extends BuiltInOperation, @isvolatile { + override string toString() { result = "__is_volatile" } + + override string getAPrimaryQlClass() { result = "BuiltInOperationIsVolatile" } +} + /** * A C/C++ `__builtin_bit_cast` built-in operation (used by some implementations * of `std::bit_cast`). diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll deleted file mode 100644 index 659940def50..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Provides a language-independent implementation of static single assignment - * (SSA) form. - */ - -private import SsaImplSpecific - -private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } - -/** - * Liveness analysis (based on source variables) to restrict the size of the - * SSA representation. - */ -private module Liveness { - /** - * A classification of variable references into reads (of a given kind) and - * (certain or uncertain) writes. - */ - private newtype TRefKind = - Read(boolean certain) { certain in [false, true] } or - Write(boolean certain) { certain in [false, true] } - - private class RefKind extends TRefKind { - string toString() { - exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") - or - exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") - } - - int getOrder() { - this = Read(_) and - result = 0 - or - this = Write(_) and - result = 1 - } - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. - */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) - or - exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) - } - - private newtype OrderedRefIndex = - MkOrderedRefIndex(int i, int tag) { - exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) - } - - private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { - ref(bb, i, v, k) and - result = MkOrderedRefIndex(i, ord) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of - * basic block `bb`, which has the given reference kind `k`. - * - * Reads are considered before writes when they happen at the same index. - */ - private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - refOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedRefIndex res | - res = refOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - private int maxRefRank(BasicBlock bb, SourceVariable v) { - result = refRank(bb, _, v, _) and - not result + 1 = refRank(bb, _, v, _) - } - - predicate lastRefIsRead(BasicBlock bb, SourceVariable v) { - maxRefRank(bb, v) = refRank(bb, _, v, Read(_)) - } - - /** - * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` - * that is either a read or a certain write. - */ - private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { - result = - min(int r, RefKind k | - r = refRank(bb, _, v, k) and - k != Write(false) - | - r - ) - } - - /** - * Holds if source variable `v` is live at the beginning of basic block `bb`. - */ - predicate liveAtEntry(BasicBlock bb, SourceVariable v) { - // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) - or - // There is no certain write to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(firstReadOrCertainWrite(bb, v)) and - liveAtExit(bb, v) - } - - /** - * Holds if source variable `v` is live at the end of basic block `bb`. - */ - predicate liveAtExit(BasicBlock bb, SourceVariable v) { - liveAtEntry(getABasicBlockSuccessor(bb), v) - } - - /** - * Holds if variable `v` is live in basic block `bb` at index `i`. - * The rank of `i` is `rnk` as defined by `refRank()`. - */ - private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { - exists(RefKind kind | rnk = refRank(bb, i, v, kind) | - rnk = maxRefRank(bb, v) and - liveAtExit(bb, v) - or - ref(bb, i, v, kind) and - kind = Read(_) - or - exists(RefKind nextKind | - liveAtRank(bb, _, v, rnk + 1) and - rnk + 1 = refRank(bb, _, v, nextKind) and - nextKind != Write(true) - ) - ) - } - - /** - * Holds if variable `v` is live after the (certain or uncertain) write at - * index `i` inside basic block `bb`. - */ - predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { - exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) - } -} - -private import Liveness - -/** - * Holds if `df` is in the dominance frontier of `bb`. - * - * This is equivalent to: - * - * ```ql - * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and - * not bb = getImmediateBasicBlockDominator+(df) - * ``` - */ -private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) - or - exists(BasicBlock prev | inDominanceFrontier(prev, df) | - bb = getImmediateBasicBlockDominator(prev) and - not bb = getImmediateBasicBlockDominator(df) - ) -} - -/** - * Holds if `bb` is in the dominance frontier of a block containing a - * definition of `v`. - */ -pragma[noinline] -private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock defbb, Definition def | - def.definesAt(v, defbb, _) and - inDominanceFrontier(defbb, bb) - ) -} - -cached -newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - -private module SsaDefReaches { - newtype TSsaRefKind = - SsaActualRead() or - SsaPhiRead() or - SsaDef() - - class SsaRead = SsaActualRead or SsaPhiRead; - - /** - * A classification of SSA variable references into reads and definitions. - */ - class SsaRefKind extends TSsaRefKind { - string toString() { - this = SsaActualRead() and - result = "SsaActualRead" - or - this = SsaPhiRead() and - result = "SsaPhiRead" - or - this = SsaDef() and - result = "SsaDef" - } - - int getOrder() { - this instanceof SsaRead and - result = 0 - or - this = SsaDef() and - result = 1 - } - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). - * - * Unlike `Liveness::ref`, this includes `phi` nodes. - */ - pragma[nomagic] - predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v, _) and - k = SsaActualRead() - or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() - } - - private newtype OrderedSsaRefIndex = - MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } - - private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { - ssaRef(bb, i, v, k) and - result = MkOrderedSsaRefIndex(i, k) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: - * - * ```ql - * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 - * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 - * ``` - * - * Reads are considered before writes when they happen at the same index. - */ - int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - ssaRefOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedSsaRefIndex res | - res = ssaRefOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - int maxSsaRefRank(BasicBlock bb, SourceVariable v) { - result = ssaRefRank(bb, _, v, _) and - not result + 1 = ssaRefRank(bb, _, v, _) - } - - /** - * Holds if the SSA definition `def` reaches rank index `rnk` in its own - * basic block `bb`. - */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { - exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) - ) - or - ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) - } - - /** - * Holds if the SSA definition of `v` at `def` reaches index `i` in the same - * basic block `bb`, without crossing another SSA definition of `v`. - */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { - exists(int rnk | - ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) - ) - } - - /** - * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. - */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, k) and - ( - ssaDefReachesRead(_, def, bb, i) - or - def.definesAt(_, bb, i) - ) - } - - /** - * Holds if the reference to `def` at index `i` in basic block `bb` is the - * last reference to `v` inside `bb`. - */ - pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) - } - - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { - exists(ssaDefRank(def, v, bb, _, k)) - } - - pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ - * predecessor of `bb2`, and the underlying variable for `def` is neither read - * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. - */ - pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and - bb2 = getABasicBlockSuccessor(bb1) - or - exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and - ssaDefReachesThroughBlock(def, mid) and - bb2 = getABasicBlockSuccessor(mid) - ) - } - - pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) - } - - pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) - or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) - ) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) - } - - pragma[nomagic] - predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 - } - - /** - * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, - * and `v` is neither read nor written in any block on the path between `bb` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | - not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) - ) - or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) - ) - } -} - -predicate phiReadExposedForTesting = phiRead/2; - -private import SsaDefReaches - -pragma[nomagic] -predicate liveThrough(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches the end of basic - * block `bb`, at which point it is still live, without crossing another - * SSA definition of `v`. - */ -pragma[nomagic] -predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { - exists(int last | - last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and - ssaDefReachesRank(bb, def, last, v) and - liveAtExit(bb, v) - ) - or - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. - */ -pragma[nomagic] -predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. - */ -pragma[nomagic] -predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(v, def, bb, i) - or - ssaRef(bb, i, v, any(SsaRead k)) and - ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read - * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a - * path between them without any read of `def`. - */ -pragma[nomagic] -predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and - bb2 = bb1 - ) - or - lastSsaRef(def, _, bb1, i1) and - defAdjacentRead(def, bb1, bb2, i2) -} - -pragma[noinline] -private predicate adjacentDefRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v -) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -private predicate adjacentDefReachesRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - ssaRef(bb1, i1, v, SsaDef()) - or - variableRead(bb1, i1, v, true) - ) - or - exists(BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `adjacentDefRead`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, true) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA definition - * `def`. The reference is last because it can reach another write `next`, - * without passing through another read or write. - */ -pragma[nomagic] -predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps - lastSsaRef(def, v, bb, i) and - exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and - 1 = ssaDefRank(next, v, bb2, _, SsaDef()) - ) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an immediately preceding definition of uncertain definition - * `def`. Since `def` is uncertain, the value from the preceding definition might - * still be valid. - */ -pragma[nomagic] -predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) -} - -private predicate adjacentDefReachesUncertainRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, false) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA - * definition `def`. - * - * That is, the node can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. - */ -pragma[nomagic] -predicate lastRef(Definition def, BasicBlock bb, int i) { - // Can reach another definition - lastRefRedef(def, bb, i, _) - or - exists(SourceVariable v | lastSsaRef(def, v, bb, i) | - // Can reach exit directly - bb instanceof ExitBasicBlock - or - // Can reach a block using one or more steps, where `def` is no longer live - varBlockReachesExit(def, bb) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { - lastRef(def, bb, i) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** A static single assignment (SSA) definition. */ -class Definition extends TDefinition { - /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { this.definesAt(result, _, _) } - - /** - * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. - * Phi nodes are considered to be at index `-1`, while normal variable writes - * are at the index of the control flow node they wrap. - */ - final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { - this = TWriteDef(v, bb, i) - or - this = TPhiNode(v, bb) and i = -1 - } - - /** Gets the basic block to which this SSA definition belongs. */ - final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - - /** Gets a textual representation of this SSA definition. */ - string toString() { none() } -} - -/** An SSA definition that corresponds to a write. */ -class WriteDefinition extends Definition, TWriteDef { - private SourceVariable v; - private BasicBlock bb; - private int i; - - WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } -} - -/** A phi node. */ -class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } -} - -/** - * An SSA definition that represents an uncertain update of the underlying - * source variable. - */ -class UncertainWriteDefinition extends WriteDefinition { - UncertainWriteDefinition() { - exists(SourceVariable v, BasicBlock bb, int i | - this.definesAt(v, bb, i) and - variableWrite(bb, i, v, false) - ) - } -} - -/** Provides a set of consistency queries. */ -module Consistency { - abstract class RelevantDefinition extends Definition { - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); - } - - query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefReachesRead(v, def, bb, i) and - not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) - } - - query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { - variableRead(bb, i, v, _) and - not ssaDefReachesRead(v, _, bb, i) - } - - query predicate deadDef(RelevantDefinition def, SourceVariable v) { - v = def.getSourceVariable() and - not ssaDefReachesRead(_, def, _, _) and - not phiHasInputFromBlock(_, def, _) and - not uncertainWriteDefinitionInput(_, def) - } - - query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | - ssaDefReachesReadWithinBlock(v, def, bb, i) and - (bb != bbDef or i < iDef) - or - ssaDefReachesRead(v, def, bb, i) and - not ssaDefReachesReadWithinBlock(v, def, bb, i) and - not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) - ) - } -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll deleted file mode 100644 index 20f9d1894b1..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll +++ /dev/null @@ -1,18 +0,0 @@ -private import semmle.code.cpp.ir.IR -private import SsaInternals as Ssa - -class BasicBlock = IRBlock; - -class SourceVariable = Ssa::SourceVariable; - -BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } - -BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - -class ExitBasicBlock extends IRBlock { - ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction } -} - -predicate variableWrite = Ssa::variableWrite/4; - -predicate variableRead = Ssa::variableRead/4; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll index 7aefc3893f2..2b86e0369bd 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll @@ -1,10 +1,10 @@ -import SsaImplCommon private import cpp as Cpp private import semmle.code.cpp.ir.IR private import DataFlowUtil private import DataFlowImplCommon as DataFlowImplCommon private import semmle.code.cpp.models.interfaces.Allocation as Alloc private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow +private import codeql.ssa.Ssa as SsaImplCommon private module SourceVariables { private newtype TSourceVariable = @@ -38,8 +38,6 @@ private module SourceVariables { } } -import SourceVariables - cached private newtype TDefOrUse = TExplicitDef(Instruction store) { explicitWrite(_, store, _) } or @@ -86,7 +84,7 @@ abstract class Def extends DefOrUse { Instruction getInstruction() { result = store } /** Gets the variable that is defined by this definition. */ - abstract SourceVariable getSourceVariable(); + abstract SourceVariables::SourceVariable getSourceVariable(); /** Holds if this definition is guaranteed to happen. */ abstract predicate isCertain(); @@ -103,10 +101,10 @@ abstract class Def extends DefOrUse { private class ExplicitDef extends Def, TExplicitDef { ExplicitDef() { this = TExplicitDef(store) } - override SourceVariable getSourceVariable() { + override SourceVariables::SourceVariable getSourceVariable() { exists(VariableInstruction var | explicitWrite(_, this.getInstruction(), var) and - result.(SourceIRVariable).getIRVariable() = var.getIRVariable() + result.(SourceVariables::SourceIRVariable).getIRVariable() = var.getIRVariable() ) } @@ -116,11 +114,11 @@ private class ExplicitDef extends Def, TExplicitDef { private class ParameterDef extends Def, TInitializeParam { ParameterDef() { this = TInitializeParam(store) } - override SourceVariable getSourceVariable() { - result.(SourceIRVariable).getIRVariable() = + override SourceVariables::SourceVariable getSourceVariable() { + result.(SourceVariables::SourceIRVariable).getIRVariable() = store.(InitializeParameterInstruction).getIRVariable() or - result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = + result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() = store.(InitializeIndirectionInstruction).getIRVariable() } @@ -138,7 +136,7 @@ abstract class Use extends DefOrUse { override string toString() { result = "Use" } /** Gets the variable that is used by this use. */ - abstract SourceVariable getSourceVariable(); + abstract SourceVariables::SourceVariable getSourceVariable(); override IRBlock getBlock() { result = use.getUse().getBlock() } @@ -148,12 +146,14 @@ abstract class Use extends DefOrUse { private class ExplicitUse extends Use, TExplicitUse { ExplicitUse() { this = TExplicitUse(use) } - override SourceVariable getSourceVariable() { + override SourceVariables::SourceVariable getSourceVariable() { exists(VariableInstruction var | use.getDef() = var and if use.getUse() instanceof ReadSideEffectInstruction - then result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = var.getIRVariable() - else result.(SourceIRVariable).getIRVariable() = var.getIRVariable() + then + result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() = + var.getIRVariable() + else result.(SourceVariables::SourceIRVariable).getIRVariable() = var.getIRVariable() ) } } @@ -161,10 +161,11 @@ private class ExplicitUse extends Use, TExplicitUse { private class ReturnParameterIndirection extends Use, TReturnParamIndirection { ReturnParameterIndirection() { this = TReturnParamIndirection(use) } - override SourceVariable getSourceVariable() { + override SourceVariables::SourceVariable getSourceVariable() { exists(ReturnIndirectionInstruction ret | returnParameterIndirection(use, ret) and - result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = ret.getIRVariable() + result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() = + ret.getIRVariable() ) } } @@ -610,27 +611,45 @@ private module Cached { import Cached -/** - * Holds if the `i`'th write in block `bb` writes to the variable `v`. - * `certain` is `true` if the write is guaranteed to overwrite the entire variable. - */ -predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) { - DataFlowImplCommon::forceCachingInSameStage() and - exists(Def def | - def.hasIndexInBlock(bb, i) and - v = def.getSourceVariable() and - (if def.isCertain() then certain = true else certain = false) - ) +private module SsaInput implements SsaImplCommon::InputSig { + private import semmle.code.cpp.ir.IR + + class BasicBlock = IRBlock; + + class SourceVariable = SourceVariables::SourceVariable; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock extends IRBlock { + ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction } + } + + /** + * Holds if the `i`'th write in block `bb` writes to the variable `v`. + * `certain` is `true` if the write is guaranteed to overwrite the entire variable. + */ + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + DataFlowImplCommon::forceCachingInSameStage() and + exists(Def def | + def.hasIndexInBlock(bb, i) and + v = def.getSourceVariable() and + (if def.isCertain() then certain = true else certain = false) + ) + } + + /** + * Holds if the `i`'th read in block `bb` reads to the variable `v`. + * `certain` is `true` if the read is guaranteed. For C++, this is always the case. + */ + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(Use use | + use.hasIndexInBlock(bb, i) and + v = use.getSourceVariable() and + certain = true + ) + } } -/** - * Holds if the `i`'th read in block `bb` reads to the variable `v`. - * `certain` is `true` if the read is guaranteed. For C++, this is always the case. - */ -predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) { - exists(Use use | - use.hasIndexInBlock(bb, i) and - v = use.getSourceVariable() and - certain = true - ) -} +import SsaImplCommon::Make diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll index 1c75529be00..873a3c635f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ -private import SSAConstruction as SSA -import SSA::SsaConsistency +private import SSAConstruction as Ssa +import Ssa::SsaConsistency diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 901735069c0..21c03e176a5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1135,7 +1135,7 @@ deprecated module SSAConsistency = SsaConsistency; * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures * that all of SSA construction will be evaluated in the same stage. */ -module SSA { +module Ssa { class MemoryLocation = Alias::MemoryLocation; predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; @@ -1144,3 +1144,6 @@ module SSA { predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } + +/** DEPRECATED: Alias for Ssa */ +deprecated module SSA = Ssa; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index b30372a791b..5564a16f215 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -20,24 +20,24 @@ newtype TInstruction = IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation ) { - UnaliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + UnaliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) } or TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc) + UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc) } or TAliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation ) { - AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + AliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) } or TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) { - AliasedSsa::SSA::hasChiInstruction(primaryInstruction) + AliasedSsa::Ssa::hasChiInstruction(primaryInstruction) } or TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - AliasedSsa::SSA::hasUnreachedInstruction(irFunc) + AliasedSsa::Ssa::hasUnreachedInstruction(irFunc) } /** @@ -50,7 +50,7 @@ module UnaliasedSsaInstructions { class TPhiInstruction = TUnaliasedSsaPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation ) { result = TUnaliasedSsaPhiInstruction(blockStartInstr, memoryLocation) } @@ -83,7 +83,7 @@ module AliasedSsaInstructions { class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation ) { result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll index 93b20865cac..684aa4f14f2 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll @@ -55,7 +55,15 @@ private predicate isDeeplyConstBelow(Type t) { isDeeplyConstBelow(t.(TypedefType).getBaseType()) } -private predicate isConstPointerLike(Type t) { +/** + * INTERNAL: Do not use. + * + * Holds if `t` is a pointer-like type (i.e., a pointer, + * an array a reference, or a pointer-wrapper such as + * `std::unique_ptr`) that is constant and only contains + * constant types, excluding the type itself. + */ +predicate isConstPointerLike(Type t) { ( t instanceof PointerWrapper or diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 36f1ce9443d..03a6422b114 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -13,8 +13,8 @@ private import TranslatedInitialization * Gets the `TranslatedDeclarationEntry` that represents the declaration * `entry`. */ -TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry) { - result.getAst() = entry +TranslatedDeclarationEntry getTranslatedDeclarationEntry(IRDeclarationEntry entry) { + result.getIRDeclarationEntry() = entry } /** @@ -24,20 +24,22 @@ TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry) * functions do not have a `TranslatedDeclarationEntry`. */ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslatedDeclarationEntry { - DeclarationEntry entry; + IRDeclarationEntry entry; TranslatedDeclarationEntry() { this = TTranslatedDeclarationEntry(entry) } final override Function getFunction() { exists(DeclStmt stmt | - stmt.getADeclarationEntry() = entry and + stmt = entry.getStmt() and result = stmt.getEnclosingFunction() ) } + IRDeclarationEntry getIRDeclarationEntry() { result = entry } + final override string toString() { result = entry.toString() } - final override Locatable getAst() { result = entry } + final override Locatable getAst() { result = entry.getAst() } /** DEPRECATED: Alias for getAst */ deprecated override Locatable getAST() { result = getAst() } @@ -216,7 +218,7 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio */ class TranslatedStaticLocalVariableInitialization extends TranslatedElement, TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization { - VariableDeclarationEntry entry; + IRVariableDeclarationEntry entry; StaticLocalVariable var; TranslatedStaticLocalVariableInitialization() { @@ -226,7 +228,7 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement, final override string toString() { result = "init: " + entry.toString() } - final override Locatable getAst() { result = entry } + final override Locatable getAst() { result = entry.getAst() } /** DEPRECATED: Alias for getAst */ deprecated override Locatable getAST() { result = getAst() } @@ -236,40 +238,6 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement, final override Function getFunction() { result = var.getFunction() } } -/** - * Gets the `TranslatedRangeBasedForVariableDeclaration` that represents the declaration of - * `var`. - */ -TranslatedRangeBasedForVariableDeclaration getTranslatedRangeBasedForVariableDeclaration( - LocalVariable var -) { - result.getVariable() = var -} - -/** - * Represents the IR translation of a compiler-generated variable in a range-based `for` loop. - */ -class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariableDeclaration, - TTranslatedRangeBasedForVariableDeclaration { - RangeBasedForStmt forStmt; - LocalVariable var; - - TranslatedRangeBasedForVariableDeclaration() { - this = TTranslatedRangeBasedForVariableDeclaration(forStmt, var) - } - - override string toString() { result = var.toString() } - - override Locatable getAst() { result = var } - - /** DEPRECATED: Alias for getAst */ - deprecated override Locatable getAST() { result = getAst() } - - override Function getFunction() { result = forStmt.getEnclosingFunction() } - - override LocalVariable getVariable() { result = var } -} - TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) { result.getAst() = expr } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 38a886746ab..3a350ea0e1a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -443,10 +443,10 @@ predicate hasTranslatedSyntheticTemporaryObject(Expr expr) { * necessary for automatic local variables, or for static local variables with dynamic * initialization. */ -private predicate translateDeclarationEntry(DeclarationEntry entry) { +private predicate translateDeclarationEntry(IRDeclarationEntry entry) { exists(DeclStmt declStmt, LocalVariable var | translateStmt(declStmt) and - declStmt.getADeclarationEntry() = entry and + declStmt = entry.getStmt() and // Only declarations of local variables need to be translated to IR. var = entry.getDeclaration() and ( @@ -458,6 +458,102 @@ private predicate translateDeclarationEntry(DeclarationEntry entry) { ) } +private module IRDeclarationEntries { + private newtype TIRDeclarationEntry = + TPresentDeclarationEntry(DeclarationEntry entry) or + TMissingDeclarationEntry(DeclStmt stmt, Declaration d, int index) { + not exists(stmt.getDeclarationEntry(index)) and + stmt.getDeclaration(index) = d + } + + /** + * An entity that represents a declaration entry in the database. + * + * This class exists to work around the fact that `DeclStmt`s in some cases + * do not have `DeclarationEntry`s. Currently, this is the case for: + * - `DeclStmt`s in template instantiations. + * - `DeclStmt`s that are generated by the desugaring of range-based for-loops. + * + * So instead, the IR works with `IRDeclarationEntry`s that synthesize missing + * `DeclarationEntry`s when there is no result for `DeclStmt::getDeclarationEntry`. + */ + abstract class IRDeclarationEntry extends TIRDeclarationEntry { + /** Gets a string representation of this `IRDeclarationEntry`. */ + abstract string toString(); + + /** Gets the `DeclStmt` that this `IRDeclarationEntry` belongs to. */ + abstract DeclStmt getStmt(); + + /** Gets the `Declaration` declared by this `IRDeclarationEntry`. */ + abstract Declaration getDeclaration(); + + /** Gets the AST represented by this `IRDeclarationEntry`. */ + abstract Locatable getAst(); + + /** + * Holds if this `IRDeclarationEntry` is the `index`'th entry + * declared by the enclosing `DeclStmt`. + */ + abstract predicate hasIndex(int index); + } + + /** A `IRDeclarationEntry` for an existing `DeclarationEntry`. */ + private class PresentDeclarationEntry extends IRDeclarationEntry, TPresentDeclarationEntry { + DeclarationEntry entry; + + PresentDeclarationEntry() { this = TPresentDeclarationEntry(entry) } + + override string toString() { result = entry.toString() } + + override DeclStmt getStmt() { result.getADeclarationEntry() = entry } + + override Declaration getDeclaration() { result = entry.getDeclaration() } + + override Locatable getAst() { result = entry } + + override predicate hasIndex(int index) { this.getStmt().getDeclarationEntry(index) = entry } + } + + /** + * A synthesized `DeclarationEntry` that is created when a `DeclStmt` is missing a + * result for `DeclStmt::getDeclarationEntry` + */ + private class MissingDeclarationEntry extends IRDeclarationEntry, TMissingDeclarationEntry { + DeclStmt stmt; + Declaration d; + int index; + + MissingDeclarationEntry() { this = TMissingDeclarationEntry(stmt, d, index) } + + override string toString() { result = "missing declaration of " + d.getName() } + + override DeclStmt getStmt() { result = stmt } + + override Declaration getDeclaration() { result = d } + + override Locatable getAst() { result = stmt } + + override predicate hasIndex(int idx) { idx = index } + } + + /** A `IRDeclarationEntry` that represents an entry for a `Variable`. */ + class IRVariableDeclarationEntry instanceof IRDeclarationEntry { + Variable v; + + IRVariableDeclarationEntry() { super.getDeclaration() = v } + + Variable getDeclaration() { result = v } + + string toString() { result = super.toString() } + + Locatable getAst() { result = super.getAst() } + + DeclStmt getStmt() { result = super.getStmt() } + } +} + +import IRDeclarationEntries + newtype TTranslatedElement = // An expression that is not being consumed as a condition TTranslatedValueExpr(Expr expr) { @@ -613,23 +709,13 @@ newtype TTranslatedElement = ) } or // A local declaration - TTranslatedDeclarationEntry(DeclarationEntry entry) { translateDeclarationEntry(entry) } or + TTranslatedDeclarationEntry(IRDeclarationEntry entry) { translateDeclarationEntry(entry) } or // The dynamic initialization of a static local variable. This is a separate object from the // declaration entry. - TTranslatedStaticLocalVariableInitialization(DeclarationEntry entry) { + TTranslatedStaticLocalVariableInitialization(IRDeclarationEntry entry) { translateDeclarationEntry(entry) and entry.getDeclaration() instanceof StaticLocalVariable } or - // A compiler-generated variable to implement a range-based for loop. These don't have a - // `DeclarationEntry` in the database, so we have to go by the `Variable` itself. - TTranslatedRangeBasedForVariableDeclaration(RangeBasedForStmt forStmt, LocalVariable var) { - translateStmt(forStmt) and - ( - var = forStmt.getRangeVariable() or - var = forStmt.getBeginEndDeclaration().getADeclaration() or - var = forStmt.getVariable() - ) - } or // An allocator call in a `new` or `new[]` expression TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or // An allocation size for a `new` or `new[]` expression diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 187dbc2f994..ee14c9847bc 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -76,6 +76,13 @@ class TranslatedDeclStmt extends TranslatedStmt { private int getChildCount() { result = count(getDeclarationEntry(_)) } + IRDeclarationEntry getIRDeclarationEntry(int index) { + result.hasIndex(index) and + result.getStmt() = stmt + } + + IRDeclarationEntry getAnIRDeclarationEntry() { result = this.getIRDeclarationEntry(_) } + /** * Gets the `TranslatedDeclarationEntry` child at zero-based index `index`. Since not all * `DeclarationEntry` objects have a `TranslatedDeclarationEntry` (e.g. extern functions), we map @@ -85,7 +92,7 @@ class TranslatedDeclStmt extends TranslatedStmt { private TranslatedDeclarationEntry getDeclarationEntry(int index) { result = rank[index + 1](TranslatedDeclarationEntry entry, int originalIndex | - entry = getTranslatedDeclarationEntry(stmt.getDeclarationEntry(originalIndex)) + entry = getTranslatedDeclarationEntry(this.getIRDeclarationEntry(originalIndex)) | entry order by originalIndex ) @@ -597,36 +604,32 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext { override RangeBasedForStmt stmt; override TranslatedElement getChild(int id) { - id = 0 and result = getRangeVariableDeclaration() + id = 0 and result = getRangeVariableDeclStmt() or - id = 1 and result = getBeginVariableDeclaration() + // Note: `__begin` and `__end` are declared by the same `DeclStmt` + id = 1 and result = getBeginEndVariableDeclStmt() or - id = 2 and result = getEndVariableDeclaration() + id = 2 and result = getCondition() or - id = 3 and result = getCondition() + id = 3 and result = getUpdate() or - id = 4 and result = getUpdate() + id = 4 and result = getVariableDeclStmt() or - id = 5 and result = getVariableDeclaration() - or - id = 6 and result = getBody() + id = 5 and result = getBody() } override Instruction getFirstInstruction() { - result = getRangeVariableDeclaration().getFirstInstruction() + result = getRangeVariableDeclStmt().getFirstInstruction() } override Instruction getChildSuccessor(TranslatedElement child) { - child = getRangeVariableDeclaration() and - result = getBeginVariableDeclaration().getFirstInstruction() + child = getRangeVariableDeclStmt() and + result = getBeginEndVariableDeclStmt().getFirstInstruction() or - child = getBeginVariableDeclaration() and - result = getEndVariableDeclaration().getFirstInstruction() - or - child = getEndVariableDeclaration() and + child = getBeginEndVariableDeclStmt() and result = getCondition().getFirstInstruction() or - child = getVariableDeclaration() and + child = getVariableDeclStmt() and result = getBody().getFirstInstruction() or child = getBody() and @@ -643,23 +646,25 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } override Instruction getChildTrueSuccessor(TranslatedCondition child) { - child = getCondition() and result = getVariableDeclaration().getFirstInstruction() + child = getCondition() and result = getVariableDeclStmt().getFirstInstruction() } override Instruction getChildFalseSuccessor(TranslatedCondition child) { child = getCondition() and result = getParent().getChildSuccessor(this) } - private TranslatedRangeBasedForVariableDeclaration getRangeVariableDeclaration() { - result = getTranslatedRangeBasedForVariableDeclaration(stmt.getRangeVariable()) + private TranslatedDeclStmt getRangeVariableDeclStmt() { + exists(IRVariableDeclarationEntry entry | + entry.getDeclaration() = stmt.getRangeVariable() and + result.getAnIRDeclarationEntry() = entry + ) } - private TranslatedRangeBasedForVariableDeclaration getBeginVariableDeclaration() { - result = getTranslatedRangeBasedForVariableDeclaration(stmt.getBeginVariable()) - } - - private TranslatedRangeBasedForVariableDeclaration getEndVariableDeclaration() { - result = getTranslatedRangeBasedForVariableDeclaration(stmt.getEndVariable()) + private TranslatedDeclStmt getBeginEndVariableDeclStmt() { + exists(IRVariableDeclarationEntry entry | + entry.getStmt() = stmt.getBeginEndDeclaration() and + result.getAnIRDeclarationEntry() = entry + ) } // Public for getInstructionBackEdgeSuccessor @@ -672,8 +677,11 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext { result = getTranslatedExpr(stmt.getUpdate().getFullyConverted()) } - private TranslatedRangeBasedForVariableDeclaration getVariableDeclaration() { - result = getTranslatedRangeBasedForVariableDeclaration(stmt.getVariable()) + private TranslatedDeclStmt getVariableDeclStmt() { + exists(IRVariableDeclarationEntry entry | + entry.getDeclaration() = stmt.getVariable() and + result.getAnIRDeclarationEntry() = entry + ) } private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 1c75529be00..873a3c635f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ -private import SSAConstruction as SSA -import SSA::SsaConsistency +private import SSAConstruction as Ssa +import Ssa::SsaConsistency diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 901735069c0..21c03e176a5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1135,7 +1135,7 @@ deprecated module SSAConsistency = SsaConsistency; * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures * that all of SSA construction will be evaluated in the same stage. */ -module SSA { +module Ssa { class MemoryLocation = Alias::MemoryLocation; predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; @@ -1144,3 +1144,6 @@ module SSA { predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } + +/** DEPRECATED: Alias for Ssa */ +deprecated module SSA = Ssa; diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll index c93a5ad147b..8c531891bcd 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll @@ -176,7 +176,7 @@ private class StdSequenceContainerInsert extends TaintFunction { ) and ( output.isQualifierObject() or - output.isReturnValueDeref() + output.isReturnValue() ) } } diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll index ae190688b70..3d2eda59799 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll @@ -543,11 +543,11 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from second parameter to first parameter - input.isParameter(1) and + input.isParameterDeref(1) and output.isParameterDeref(0) or // flow from second parameter to return value - input.isParameter(1) and + input.isParameterDeref(1) and output.isReturnValueDeref() or // reverse flow from returned reference to the first parameter diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll index 1a65e7b6ca4..e729c3cb0a4 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll @@ -61,7 +61,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid input.isParameterDeref(0) and output.isParameterDeref(0) or - input.isParameter(1) and + input.isParameterDeref(1) and output.isParameterDeref(0) } diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index 5e899be68d4..de44913a39f 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -46,6 +46,26 @@ class FunctionInput extends TFunctionInput { */ deprecated final predicate isInParameter(ParameterIndex index) { this.isParameter(index) } + /** + * Holds if this is the input value pointed to (through `ind` number of indirections) by a + * pointer parameter to a function, or the input value referred to by a reference parameter + * to a function, where the parameter has index `index`. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - `isParameterDeref(1, 1)` holds for the `FunctionInput` that represents the value of `*p` (with + * type `char`) on entry to the function. + * - `isParameterDeref(2, 1)` holds for the `FunctionInput` that represents the value of `r` (with type + * `float`) on entry to the function. + * - There is no `FunctionInput` for which `isParameterDeref(0, _)` holds, because `n` is neither a + * pointer nor a reference. + */ + predicate isParameterDeref(ParameterIndex index, int ind) { + ind = 1 and this.isParameterDeref(index) + } + /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input * value referred to by a reference parameter to a function, where the parameter has index @@ -62,7 +82,7 @@ class FunctionInput extends TFunctionInput { * - There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a * pointer nor a reference. */ - predicate isParameterDeref(ParameterIndex index) { none() } + predicate isParameterDeref(ParameterIndex index) { this.isParameterDeref(index, 1) } /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input @@ -87,7 +107,22 @@ class FunctionInput extends TFunctionInput { * - `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` * (with type `C const`) on entry to the function. */ - predicate isQualifierObject() { none() } + predicate isQualifierObject(int ind) { ind = 1 and this.isQualifierObject() } + + /** + * Holds if this is the input value pointed to by the `this` pointer of an instance member + * function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` + * (with type `C const`) on entry to the function. + */ + predicate isQualifierObject() { this.isQualifierObject(1) } /** * Holds if this is the input value pointed to by the `this` pointer of an instance member @@ -143,16 +178,49 @@ class FunctionInput extends TFunctionInput { * rare, but they do occur when a function returns a reference to itself, * part of itself, or one of its other inputs. */ - predicate isReturnValueDeref() { none() } + predicate isReturnValueDeref() { this.isReturnValueDeref(1) } + + /** + * Holds if this is the input value pointed to by the return value of a + * function, if the function returns a pointer, or the input value referred + * to by the return value of a function, if the function returns a reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `isReturnValueDeref(1)` holds for the `FunctionInput` that represents the + * value of `*getPointer()` (with type `char`). + * - `isReturnValueDeref(1)` holds for the `FunctionInput` that represents the + * value of `getReference()` (with type `float`). + * - There is no `FunctionInput` of `getInt()` for which + * `isReturnValueDeref(_)` holds because the return type of `getInt()` is + * neither a pointer nor a reference. + * + * Note that data flows in through function return values are relatively + * rare, but they do occur when a function returns a reference to itself, + * part of itself, or one of its other inputs. + */ + predicate isReturnValueDeref(int ind) { ind = 1 and this.isReturnValueDeref() } + + /** + * Holds if `i >= 0` and `isParameterDeref(i, ind)` holds for this value, or + * if `i = -1` and `isQualifierObject(ind)` holds for this value. + */ + final predicate isParameterDerefOrQualifierObject(ParameterIndex i, int ind) { + i >= 0 and this.isParameterDeref(i, ind) + or + i = -1 and this.isQualifierObject(ind) + } /** * Holds if `i >= 0` and `isParameterDeref(i)` holds for this value, or * if `i = -1` and `isQualifierObject()` holds for this value. */ final predicate isParameterDerefOrQualifierObject(ParameterIndex i) { - i >= 0 and this.isParameterDeref(i) - or - i = -1 and this.isQualifierObject() + this.isParameterDerefOrQualifierObject(i, 1) } } @@ -308,7 +376,25 @@ class FunctionOutput extends TFunctionOutput { * - There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a * pointer nor a reference. */ - predicate isParameterDeref(ParameterIndex i) { none() } + predicate isParameterDeref(ParameterIndex i) { this.isParameterDeref(i, 1) } + + /** + * Holds if this is the output value pointed to by a pointer parameter (through `ind` number + * of indirections) to a function, or the output value referred to by a reference parameter to + * a function, where the parameter has index `index`. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - `isParameterDeref(1, 1)` holds for the `FunctionOutput` that represents the value of `*p` (with + * type `char`) on return from the function. + * - `isParameterDeref(2, 1)` holds for the `FunctionOutput` that represents the value of `r` (with + * type `float`) on return from the function. + * - There is no `FunctionOutput` for which `isParameterDeref(0, _)` holds, because `n` is neither a + * pointer nor a reference. + */ + predicate isParameterDeref(ParameterIndex i, int ind) { ind = 1 and this.isParameterDeref(i) } /** * Holds if this is the output value pointed to by a pointer parameter to a function, or the @@ -333,7 +419,22 @@ class FunctionOutput extends TFunctionOutput { * - `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` * (with type `C`) on return from the function. */ - predicate isQualifierObject() { none() } + predicate isQualifierObject() { this.isQualifierObject(1) } + + /** + * Holds if this is the output value pointed to by the `this` pointer of an instance member + * function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r); + * }; + * ``` + * - `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` + * (with type `C`) on return from the function. + */ + predicate isQualifierObject(int ind) { ind = 1 and this.isQualifierObject() } /** * Holds if this is the output value pointed to by the `this` pointer of an instance member @@ -385,7 +486,27 @@ class FunctionOutput extends TFunctionOutput { * - There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the * return type of `getInt()` is neither a pointer nor a reference. */ - predicate isReturnValueDeref() { none() } + predicate isReturnValueDeref() { this.isReturnValueDeref(_) } + + /** + * Holds if this is the output value pointed to by the return value of a function, if the function + * returns a pointer, or the output value referred to by the return value of a function, if the + * function returns a reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `isReturnValueDeref(1)` holds for the `FunctionOutput` that represents the value of + * `*getPointer()` (with type `char`). + * - `isReturnValueDeref(1)` holds for the `FunctionOutput` that represents the value of + * `getReference()` (with type `float`). + * - There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref(_)` holds because the + * return type of `getInt()` is neither a pointer nor a reference. + */ + predicate isReturnValueDeref(int ind) { ind = 1 and this.isReturnValueDeref() } /** * Holds if this is the output value pointed to by the return value of a function, if the function @@ -395,14 +516,22 @@ class FunctionOutput extends TFunctionOutput { */ deprecated final predicate isOutReturnPointer() { this.isReturnValueDeref() } + /** + * Holds if `i >= 0` and `isParameterDeref(i, ind)` holds for this is the value, or + * if `i = -1` and `isQualifierObject(ind)` holds for this value. + */ + final predicate isParameterDerefOrQualifierObject(ParameterIndex i, int ind) { + i >= 0 and this.isParameterDeref(i, ind) + or + i = -1 and this.isQualifierObject(ind) + } + /** * Holds if `i >= 0` and `isParameterDeref(i)` holds for this is the value, or * if `i = -1` and `isQualifierObject()` holds for this value. */ final predicate isParameterDerefOrQualifierObject(ParameterIndex i) { - i >= 0 and this.isParameterDeref(i) - or - i = -1 and this.isQualifierObject() + this.isParameterDerefOrQualifierObject(i, 1) } } @@ -431,6 +560,10 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { ParameterIndex getIndex() { result = index } override predicate isParameterDeref(ParameterIndex i) { i = index } + + override predicate isParameterDeref(ParameterIndex i, int ind) { + this.isParameterDeref(i) and ind = 1 + } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/pointsto/PointsTo.qll b/cpp/ql/lib/semmle/code/cpp/pointsto/PointsTo.qll index 83b8c2936f0..542ce985060 100644 --- a/cpp/ql/lib/semmle/code/cpp/pointsto/PointsTo.qll +++ b/cpp/ql/lib/semmle/code/cpp/pointsto/PointsTo.qll @@ -19,6 +19,10 @@ * `pointstoinfo` predicate determines the transitively implied points-to * information by collapsing pointers into equivalence classes. These * equivalence classes are called "points-to sets". + * + * WARNING: This library may perform poorly on very large projects. + * Consider using another library such as `semmle.code.cpp.dataflow.DataFlow` + * instead. */ import semmle.code.cpp.commons.File diff --git a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll b/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll index d5e69d31254..7dd55dbfde3 100644 --- a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll @@ -165,7 +165,7 @@ private ControlFlowNode mostRecentSideEffect(ControlFlowNode node) { /** Used to represent the "global value number" of an expression. */ cached -private newtype GVNBase = +private newtype GvnBase = GVN_IntConst(int val, Type t) { mk_IntConst(val, t, _) } or GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or // If the local variable does not have a defining value, then @@ -221,8 +221,8 @@ private newtype GVNBase = * expression with this `GVN` and using its `toString` and `getLocation` * methods. */ -class GVN extends GVNBase { - GVN() { this instanceof GVNBase } +class GVN extends GvnBase { + GVN() { this instanceof GvnBase } /** Gets an expression that has this GVN. */ Expr getAnExpr() { this = globalValueNumber(result) } diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index f96ad9b2da4..625f706f2a4 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -746,7 +746,7 @@ type_mentions( unique int id: @type_mention, int type_id: @type ref, int location: @location ref, - // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + // a_symbol_reference_kind from the frontend. int kind: int ref ); @@ -1596,7 +1596,7 @@ case @expr.kind of | 117 = @ispolyexpr // __is_polymorphic ::= type | 118 = @isunionexpr // __is_union ::= type | 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type -| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof // ... | 122 = @hastrivialdestructor // __has_trivial_destructor ::= type | 123 = @literal @@ -1666,6 +1666,33 @@ case @expr.kind of | 333 = @builtinbitcast | 334 = @builtinshuffle | 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile ; @var_args_expr = @vastartexpr @@ -1732,6 +1759,33 @@ case @expr.kind of | @hasuniqueobjectrepresentations | @builtinbitcast | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile ; new_allocated_type( diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats index 7fb9f2c2e4d..69f7841b64c 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats @@ -16,21 +16,21 @@ @svnentry 575525 + + @location_default + 29655085 + @location_stmt - 3813503 + 3813506 @location_expr - 13165921 - - - @location_default - 29655056 + 13165934 @diagnostic - 72092 + 72091 @file @@ -42,27 +42,27 @@ @macroinvocation - 33818017 + 34146969 @function - 4628077 + 4628081 @fun_decl - 4995583 + 4995588 @var_decl - 8391080 + 8391088 @type_decl - 3240440 + 3240444 @namespace_decl - 307432 + 307431 @using @@ -74,23 +74,23 @@ @parameter - 6536424 + 6536430 @membervariable - 1052962 + 1052936 @globalvariable - 300708 + 301270 @localvariable - 581177 + 581167 @enumconstant - 241273 + 241267 @builtintype @@ -98,7 +98,7 @@ @derivedtype - 4324907 + 4324912 @decltype @@ -106,19 +106,19 @@ @usertype - 5230250 + 5230255 @mangledname - 2114402 + 2114368 @type_mention - 4022510 + 4022409 @routinetype - 547156 + 547157 @ptrtomember @@ -128,26 +128,6 @@ @specifier 24531 - - @gnuattribute - 680858 - - - @stdattribute - 493039 - - - @alignas - 9719 - - - @declspec - 243695 - - - @msattribute - 3 - @attribute_arg_token 38879 @@ -168,17 +148,37 @@ @attribute_arg_constant 1 + + @gnuattribute + 680858 + + + @stdattribute + 493031 + + + @alignas + 9719 + + + @declspec + 243692 + + + @msattribute + 3 + @derivation 368264 @frienddecl - 716133 + 716134 @comment - 8773472 + 8773331 @namespace @@ -190,15 +190,15 @@ @namequalifier - 1533107 + 1533108 @value - 10759270 + 10759479 @initialiser - 1699581 + 1699574 @lambdacapture @@ -214,15 +214,15 @@ @reference_to - 1592318 + 1592319 @indirect - 292162 + 292157 @ref_indirect - 1938635 + 1938637 @array_to_pointer @@ -234,7 +234,7 @@ @parexpr - 3581771 + 3581772 @arithnegexpr @@ -246,11 +246,11 @@ @notexpr - 275941 + 275934 @postincrexpr - 61943 + 61942 @postdecrexpr @@ -270,7 +270,7 @@ @addexpr - 397789 + 397795 @subexpr @@ -278,11 +278,11 @@ @mulexpr - 305921 + 305914 @divexpr - 132913 + 132910 @remexpr @@ -290,35 +290,35 @@ @paddexpr - 86519 + 86517 @psubexpr - 49818 + 49816 @pdiffexpr - 35456 + 35455 @lshiftexpr - 565473 + 565465 @rshiftexpr - 140572 + 140568 @andexpr - 488189 + 488177 @orexpr - 145188 + 145184 @xorexpr - 54086 + 54084 @eqexpr @@ -338,15 +338,15 @@ @geexpr - 59151 + 59150 @leexpr - 212175 + 212171 @assignexpr - 935391 + 935392 @assignaddexpr @@ -378,7 +378,7 @@ @assignandexpr - 4817 + 4816 @assignorexpr @@ -398,15 +398,15 @@ @orlogicalexpr - 864675 + 864670 @commaexpr - 124044 + 124042 @subscriptexpr - 367585 + 367579 @callexpr @@ -426,11 +426,11 @@ @varaccess - 6019055 + 6019061 @thisaccess - 1127165 + 1127159 @new_expr @@ -458,7 +458,7 @@ @runtime_sizeof - 295484 + 295477 @runtime_alignof @@ -470,11 +470,11 @@ @routineexpr - 2917668 + 2917671 @type_operand - 1126886 + 1126879 @isemptyexpr @@ -490,7 +490,7 @@ @literal - 4406598 + 4406610 @aggregateliteral @@ -506,7 +506,7 @@ @ctordirectinit - 112980 + 112981 @ctorvirtualinit @@ -534,7 +534,7 @@ @static_cast - 210928 + 210926 @reinterpret_cast @@ -542,7 +542,7 @@ @const_cast - 35247 + 35246 @dynamic_cast @@ -654,7 +654,7 @@ @expr_stmt - 94228 + 94226 @offsetofexpr @@ -730,7 +730,7 @@ @typescompexpr - 562843 + 562840 @intaddrexpr @@ -834,7 +834,7 @@ @builtinchooseexpr - 9069 + 9068 @vec_fill @@ -884,9 +884,117 @@ @blockassignexpr 12 + + @issame + 2 + + + @isfunction + 2 + + + @islayoutcompatible + 2 + + + @ispointerinterconvertiblebaseof + 2 + + + @isarray + 2 + + + @arrayrank + 2 + + + @arrayextent + 3 + + + @isarithmetic + 2 + + + @iscompletetype + 2 + + + @iscompound + 2 + + + @isconst + 2 + + + @isfloatingpoint + 2 + + + @isfundamental + 2 + + + @isintegral + 2 + + + @islvaluereference + 2 + + + @ismemberfunctionpointer + 2 + + + @ismemberobjectpointer + 2 + + + @ismemberpointer + 3 + + + @isobject + 2 + + + @ispointer + 2 + + + @isreference + 2 + + + @isrvaluereference + 2 + + + @isscalar + 2 + + + @issigned + 2 + + + @isunsigned + 2 + + + @isvoid + 2 + + + @isvolatile + 2 + @stmt_expr - 1483542 + 1483544 @stmt_if @@ -898,19 +1006,19 @@ @stmt_label - 53054 + 53053 @stmt_return - 1285345 + 1285346 @stmt_block - 1423276 + 1423277 @stmt_end_test_while - 148628 + 148625 @stmt_for @@ -922,7 +1030,7 @@ @stmt_switch - 20747 + 20746 @stmt_try_block @@ -930,19 +1038,19 @@ @stmt_decl - 606536 + 606532 @stmt_empty - 193314 + 193310 @stmt_continue - 22525 + 22524 @stmt_break - 102345 + 102344 @stmt_range_based_for @@ -954,15 +1062,15 @@ @stmt_constexpr_if - 52504 + 52503 @stmt_goto - 110508 + 110506 @stmt_asm - 109773 + 109770 @stmt_microsoft_try @@ -986,7 +1094,7 @@ @ppd_if - 661418 + 661419 @ppd_ifdef @@ -1006,7 +1114,7 @@ @ppd_endif - 1186757 + 1186758 @ppd_plain_include @@ -1014,7 +1122,7 @@ @ppd_define - 2433089 + 2433050 @ppd_undef @@ -1022,7 +1130,7 @@ @ppd_pragma - 311993 + 311988 @ppd_include_next @@ -1030,7 +1138,7 @@ @ppd_line - 27756 + 27755 @ppd_error @@ -1124,7 +1232,7 @@ compilation_args - 651309 + 651293 id @@ -1136,7 +1244,7 @@ arg - 34395 + 34394 @@ -1160,7 +1268,7 @@ 126 127 - 3861 + 3860 127 @@ -1201,7 +1309,7 @@ 106 107 - 3824 + 3823 107 @@ -1374,7 +1482,7 @@ 1 2 - 32335 + 32334 2 @@ -1395,7 +1503,7 @@ 1 2 - 33191 + 33190 2 @@ -1410,7 +1518,7 @@ compilation_compiling_files - 11527 + 11526 id @@ -1538,7 +1646,7 @@ 1 2 - 1755 + 1754 2 @@ -1574,7 +1682,7 @@ 1 2 - 1755 + 1754 2 @@ -1656,7 +1764,7 @@ compilation_time - 46108 + 46107 id @@ -1672,7 +1780,7 @@ seconds - 10330 + 11287 @@ -1753,48 +1861,48 @@ 3 4 - 678 + 757 4 5 - 319 + 279 6 - 8 - 119 + 9 + 159 - 8 + 9 10 - 159 + 119 10 11 - 79 + 159 11 - 13 - 159 - - - 15 - 18 - 159 + 16 + 119 18 - 22 + 19 159 - 25 - 92 + 19 + 43 159 + + 57 + 112 + 79 + @@ -1809,7 +1917,7 @@ 1 2 - 1755 + 1754 2 @@ -1861,27 +1969,27 @@ 3 4 - 1396 + 1316 4 5 - 358 + 438 5 6 - 199 + 239 6 7 - 478 + 319 7 8 - 39 + 159 8 @@ -1890,13 +1998,13 @@ 9 - 24 - 239 + 26 + 279 - 25 - 90 - 279 + 27 + 94 + 239 @@ -1952,13 +2060,13 @@ 39 - 128 - 129 + 137 + 138 39 - 133 - 134 + 148 + 149 39 @@ -1975,27 +2083,22 @@ 1 2 - 6062 + 6222 2 3 - 2034 + 3031 3 4 - 917 + 1196 4 - 5 - 797 - - - 5 - 42 - 518 + 44 + 837 @@ -2011,32 +2114,27 @@ 1 2 - 5225 + 5384 2 3 - 1874 + 2991 3 4 - 1276 + 1435 4 5 - 997 + 757 5 - 9 - 797 - - - 9 - 65 - 159 + 66 + 717 @@ -2052,12 +2150,12 @@ 1 2 - 10051 + 10928 2 - 4 - 279 + 3 + 358 @@ -2067,11 +2165,11 @@ diagnostic_for - 889095 + 889089 diagnostic - 72092 + 72091 compilation @@ -2102,7 +2200,7 @@ 2 3 - 59654 + 59653 254 @@ -2123,7 +2221,7 @@ 1 2 - 72092 + 72091 @@ -2139,7 +2237,7 @@ 1 2 - 72092 + 72091 @@ -2436,7 +2534,7 @@ cpu_seconds - 7792 + 7538 elapsed_seconds @@ -2486,17 +2584,17 @@ 1 2 - 6489 + 6201 2 3 - 922 + 910 3 - 19 - 380 + 11 + 426 @@ -2512,12 +2610,12 @@ 1 2 - 7319 + 7020 2 3 - 472 + 518 @@ -2538,56 +2636,51 @@ 2 3 - 23 + 11 3 4 + 23 + + + 8 + 9 11 - 7 - 8 + 9 + 10 + 23 + + + 18 + 19 11 - 10 - 11 + 52 + 53 11 - 11 - 12 + 107 + 108 11 - 26 - 27 + 159 + 160 11 - 51 - 52 + 239 + 240 11 - 160 - 161 - 11 - - - 172 - 173 - 11 - - - 198 - 199 - 11 - - - 219 - 220 + 252 + 253 11 @@ -2609,31 +2702,26 @@ 2 3 - 23 + 11 3 4 + 23 + + + 8 + 9 11 - 7 - 8 - 11 + 9 + 10 + 23 - 10 - 11 - 11 - - - 11 - 12 - 11 - - - 24 - 25 + 18 + 19 11 @@ -2642,23 +2730,23 @@ 11 - 115 - 116 + 98 + 99 11 - 140 - 141 + 114 + 115 11 - 155 - 156 + 168 + 169 11 - 197 - 198 + 216 + 217 11 @@ -4383,11 +4471,11 @@ locations_default - 29655056 + 29655085 id - 29655056 + 29655085 container @@ -4395,7 +4483,7 @@ startLine - 2080991 + 2080993 startColumn @@ -4403,11 +4491,11 @@ endLine - 2083768 + 2083770 endColumn - 47673 + 47674 @@ -4421,7 +4509,7 @@ 1 2 - 29655056 + 29655085 @@ -4437,7 +4525,7 @@ 1 2 - 29655056 + 29655085 @@ -4453,7 +4541,7 @@ 1 2 - 29655056 + 29655085 @@ -4469,7 +4557,7 @@ 1 2 - 29655056 + 29655085 @@ -4485,7 +4573,7 @@ 1 2 - 29655056 + 29655085 @@ -4876,7 +4964,7 @@ 1 2 - 572087 + 572088 2 @@ -4937,12 +5025,12 @@ 1 2 - 855354 + 855355 2 3 - 275860 + 275861 3 @@ -4993,12 +5081,12 @@ 2 3 - 308260 + 308261 3 4 - 199952 + 199953 4 @@ -5008,7 +5096,7 @@ 6 9 - 177735 + 177736 9 @@ -5044,17 +5132,17 @@ 1 2 - 1520938 + 1520939 2 3 - 345751 + 345752 3 5 - 161998 + 161999 5 @@ -5592,7 +5680,7 @@ 1 2 - 866925 + 866926 2 @@ -5607,7 +5695,7 @@ 4 6 - 139781 + 139782 6 @@ -5617,7 +5705,7 @@ 10 15 - 165238 + 165239 15 @@ -5648,12 +5736,12 @@ 1 2 - 1513995 + 1513996 2 3 - 343437 + 343438 3 @@ -5694,7 +5782,7 @@ 4 6 - 184215 + 184216 6 @@ -5709,7 +5797,7 @@ 13 19 - 171718 + 171719 19 @@ -6170,11 +6258,11 @@ locations_stmt - 3813503 + 3813506 id - 3813503 + 3813506 container @@ -6208,7 +6296,7 @@ 1 2 - 3813503 + 3813506 @@ -6224,7 +6312,7 @@ 1 2 - 3813503 + 3813506 @@ -6240,7 +6328,7 @@ 1 2 - 3813503 + 3813506 @@ -6256,7 +6344,7 @@ 1 2 - 3813503 + 3813506 @@ -6272,7 +6360,7 @@ 1 2 - 3813503 + 3813506 @@ -7641,7 +7729,7 @@ 3 4 - 16832 + 16833 4 @@ -7651,7 +7739,7 @@ 5 6 - 18579 + 18580 6 @@ -8152,15 +8240,15 @@ locations_expr - 13165921 + 13165934 id - 13165921 + 13165934 container - 4644 + 4645 startLine @@ -8190,7 +8278,7 @@ 1 2 - 13165921 + 13165934 @@ -8206,7 +8294,7 @@ 1 2 - 13165921 + 13165934 @@ -8222,7 +8310,7 @@ 1 2 - 13165921 + 13165934 @@ -8238,7 +8326,7 @@ 1 2 - 13165921 + 13165934 @@ -8254,7 +8342,7 @@ 1 2 - 13165921 + 13165934 @@ -10084,11 +10172,11 @@ numlines - 1383933 + 1383934 element_id - 1376990 + 1376992 num_lines @@ -10114,7 +10202,7 @@ 1 2 - 1370047 + 1370049 2 @@ -10135,7 +10223,7 @@ 1 2 - 1370973 + 1370974 2 @@ -10156,7 +10244,7 @@ 1 2 - 1376990 + 1376992 @@ -10208,7 +10296,7 @@ 1 2 - 69890 + 69891 2 @@ -10500,11 +10588,11 @@ diagnostics - 72092 + 72091 id - 72092 + 72091 severity @@ -10538,7 +10626,7 @@ 1 2 - 72092 + 72091 @@ -10554,7 +10642,7 @@ 1 2 - 72092 + 72091 @@ -10570,7 +10658,7 @@ 1 2 - 72092 + 72091 @@ -10586,7 +10674,7 @@ 1 2 - 72092 + 72091 @@ -10602,7 +10690,7 @@ 1 2 - 72092 + 72091 @@ -11033,7 +11121,7 @@ 1 2 - 62536 + 62535 829 @@ -11308,7 +11396,7 @@ containerparent - 136541 + 136542 parent @@ -11316,7 +11404,7 @@ child - 136541 + 136542 @@ -11371,7 +11459,7 @@ 1 2 - 136541 + 136542 @@ -11381,7 +11469,7 @@ fileannotations - 5237857 + 5237823 id @@ -11397,7 +11485,7 @@ value - 47020 + 47019 @@ -11739,7 +11827,7 @@ 6 9 - 4219 + 4218 9 @@ -11749,7 +11837,7 @@ 14 17 - 4219 + 4218 17 @@ -11897,7 +11985,7 @@ 5 8 - 3585 + 3584 8 @@ -11917,7 +12005,7 @@ 19 29 - 3585 + 3584 29 @@ -11957,15 +12045,15 @@ inmacroexpansion - 109604497 + 109604545 id - 17996941 + 17997566 inv - 2695871 + 2695876 @@ -11979,37 +12067,37 @@ 1 3 - 1578646 + 1579270 3 5 - 1074226 + 1074227 5 6 - 1182860 + 1182861 6 7 - 4812393 + 4812395 7 8 - 6375799 + 6375802 8 9 - 2601948 + 2601949 9 - 150 - 371065 + 21 + 371061 @@ -12025,12 +12113,12 @@ 1 2 - 377822 + 377823 2 3 - 543239 + 543242 3 @@ -12050,7 +12138,7 @@ 8 9 - 241503 + 241504 9 @@ -12060,7 +12148,7 @@ 10 11 - 324968 + 324969 11 @@ -12085,15 +12173,15 @@ affectedbymacroexpansion - 35632294 + 35632309 id - 5148536 + 5148539 inv - 2780342 + 2780344 @@ -12107,7 +12195,7 @@ 1 2 - 2811452 + 2811454 2 @@ -12153,7 +12241,7 @@ 1 4 - 228751 + 228752 4 @@ -12223,11 +12311,11 @@ macroinvocations - 33818017 + 34146969 id - 33818017 + 34146969 macro_id @@ -12235,7 +12323,7 @@ location - 776461 + 776502 kind @@ -12253,7 +12341,7 @@ 1 2 - 33818017 + 34146969 @@ -12269,7 +12357,7 @@ 1 2 - 33818017 + 34146969 @@ -12285,7 +12373,7 @@ 1 2 - 33818017 + 34146969 @@ -12301,57 +12389,57 @@ 1 2 - 17521 + 16645 2 3 - 16922 + 16979 3 4 - 3688 + 3181 4 5 - 4853 + 5348 5 8 - 6005 + 5890 8 - 14 - 6432 + 13 + 6270 - 14 - 29 - 6305 + 13 + 26 + 6259 - 29 - 73 - 6201 + 26 + 61 + 6213 - 73 - 257 - 6097 + 61 + 205 + 6132 - 257 - 5161 - 6097 + 205 + 1780 + 6109 - 5432 - 168296 - 1048 + 1780 + 168526 + 2144 @@ -12367,7 +12455,7 @@ 1 2 - 43366 + 43365 2 @@ -12377,7 +12465,7 @@ 3 4 - 5268 + 5267 4 @@ -12413,7 +12501,7 @@ 1 2 - 75308 + 75307 2 @@ -12434,37 +12522,42 @@ 1 2 - 320046 + 288516 2 3 - 170824 + 173555 3 4 - 50732 + 72483 4 5 - 61717 + 60990 5 - 9 - 68887 + 8 + 54639 - 9 - 23 - 58340 + 8 + 17 + 63538 - 23 - 244365 - 45913 + 17 + 628 + 58247 + + + 632 + 244541 + 4530 @@ -12480,12 +12573,12 @@ 1 2 - 729337 + 729355 2 350 - 47123 + 47146 @@ -12501,7 +12594,7 @@ 1 2 - 776461 + 776502 @@ -12515,13 +12608,13 @@ 12 - 20464 - 20465 + 20671 + 20672 11 - 2913248 - 2913249 + 2941597 + 2941598 11 @@ -12562,8 +12655,8 @@ 11 - 61043 - 61044 + 61047 + 61048 11 @@ -12574,15 +12667,15 @@ macroparent - 30368148 + 30547394 id - 30368148 + 30547394 parent_id - 23632653 + 23742572 @@ -12596,7 +12689,7 @@ 1 2 - 30368148 + 30547394 @@ -12612,17 +12705,17 @@ 1 2 - 18259095 + 18336300 2 3 - 4525350 + 4553885 3 88 - 848207 + 852386 @@ -12632,15 +12725,15 @@ macrolocationbind - 4036896 + 4037048 id - 2826220 + 2826423 location - 2017729 + 2017695 @@ -12654,22 +12747,22 @@ 1 2 - 2225956 + 2226199 2 3 - 340592 + 340555 3 7 - 230144 + 230140 7 57 - 29528 + 29527 @@ -12685,22 +12778,22 @@ 1 2 - 1608672 + 1608334 2 3 - 177047 + 177385 3 8 - 156640 + 156607 8 723 - 75368 + 75366 @@ -12710,11 +12803,11 @@ macro_argument_unexpanded - 85909146 + 86237561 invocation - 26486648 + 26718658 argument_index @@ -12722,7 +12815,7 @@ text - 325037 + 325035 @@ -12736,22 +12829,22 @@ 1 2 - 7413109 + 7569359 2 3 - 10827242 + 10882987 3 4 - 6239771 + 6259004 4 67 - 2006525 + 2007307 @@ -12767,22 +12860,22 @@ 1 2 - 7484094 + 7640355 2 3 - 10976626 + 11032911 3 4 - 6070745 + 6089437 4 67 - 1955182 + 1955953 @@ -12802,12 +12895,12 @@ 41432 - 174067 + 174136 57 - 715366 - 2297717 + 717107 + 2317859 34 @@ -12850,57 +12943,57 @@ 1 2 - 40726 + 37325 2 3 - 65394 + 64645 3 4 - 15135 + 16979 4 5 - 44945 + 45740 5 8 - 25510 + 25521 8 12 - 16000 + 16357 12 16 - 22213 + 21752 16 23 - 26420 + 25682 23 - 43 - 24691 + 42 + 24495 - 43 - 165 - 24391 + 42 + 129 + 24403 - 165 - 521384 - 19608 + 129 + 522100 + 22132 @@ -12916,7 +13009,7 @@ 1 2 - 235066 + 235064 2 @@ -12936,11 +13029,11 @@ macro_argument_expanded - 85909146 + 86237561 invocation - 26486648 + 26718658 argument_index @@ -12948,7 +13041,7 @@ text - 196979 + 196978 @@ -12962,22 +13055,22 @@ 1 2 - 7413109 + 7569359 2 3 - 10827242 + 10882987 3 4 - 6239771 + 6259004 4 67 - 2006525 + 2007307 @@ -12993,22 +13086,22 @@ 1 2 - 10713329 + 10891563 2 3 - 9344510 + 9381278 3 4 - 5293039 + 5309327 4 9 - 1135769 + 1136488 @@ -13028,12 +13121,12 @@ 41432 - 174067 + 174136 57 - 715366 - 2297717 + 717107 + 2317859 34 @@ -13076,62 +13169,62 @@ 1 2 - 24472 + 22017 2 3 - 41025 + 39746 3 4 - 6904 + 8876 4 5 - 16311 + 16772 5 6 - 2985 + 3054 6 7 - 23204 + 22720 7 - 9 - 15953 + 10 + 16195 - 9 + 10 15 - 16622 + 15757 15 - 31 - 15527 + 27 + 14939 - 31 - 97 - 15054 + 27 + 73 + 14916 - 97 - 775 - 15446 + 73 + 361 + 14824 - 775 - 1052972 - 3469 + 363 + 1059615 + 7158 @@ -13152,7 +13245,7 @@ 2 3 - 82582 + 82581 3 @@ -13167,15 +13260,15 @@ functions - 4628077 + 4628081 id - 4628077 + 4628081 name - 1902792 + 1902794 kind @@ -13193,7 +13286,7 @@ 1 2 - 4628077 + 4628081 @@ -13209,7 +13302,7 @@ 1 2 - 4628077 + 4628081 @@ -13225,7 +13318,7 @@ 1 2 - 1492704 + 1492705 2 @@ -13235,7 +13328,7 @@ 3 5 - 149038 + 149039 5 @@ -13256,7 +13349,7 @@ 1 2 - 1902329 + 1902331 2 @@ -13363,15 +13456,15 @@ function_entry_point - 1158060 + 1158061 id - 1148340 + 1148341 entry_point - 1158060 + 1158061 @@ -13385,7 +13478,7 @@ 1 2 - 1138620 + 1138621 2 @@ -13406,7 +13499,7 @@ 1 2 - 1158060 + 1158061 @@ -13416,15 +13509,15 @@ function_return_type - 4636408 + 4636413 id - 4628077 + 4628081 return_type - 990970 + 990971 @@ -13438,7 +13531,7 @@ 1 2 - 4621134 + 4621138 2 @@ -13818,22 +13911,22 @@ function_defaulted - 73130 + 73131 id - 73130 + 73131 member_function_this_type - 553401 + 553402 id - 553401 + 553402 this_type @@ -13851,7 +13944,7 @@ 1 2 - 553401 + 553402 @@ -13902,27 +13995,27 @@ fun_decls - 5000674 + 5000679 id - 4995583 + 4995588 function - 4485518 + 4485522 type_id - 989581 + 989582 name - 1806056 + 1806058 location - 3404291 + 3404294 @@ -13936,7 +14029,7 @@ 1 2 - 4995583 + 4995588 @@ -13952,7 +14045,7 @@ 1 2 - 4990491 + 4990496 2 @@ -13973,7 +14066,7 @@ 1 2 - 4995583 + 4995588 @@ -13989,7 +14082,7 @@ 1 2 - 4995583 + 4995588 @@ -14005,7 +14098,7 @@ 1 2 - 4055063 + 4055067 2 @@ -14015,7 +14108,7 @@ 3 7 - 73130 + 73131 @@ -14031,7 +14124,7 @@ 1 2 - 4444324 + 4444328 2 @@ -14052,7 +14145,7 @@ 1 2 - 4485518 + 4485522 @@ -14068,7 +14161,7 @@ 1 2 - 4111069 + 4111073 2 @@ -14094,12 +14187,12 @@ 1 2 - 438785 + 438786 2 3 - 438785 + 438786 3 @@ -14130,7 +14223,7 @@ 2 3 - 368431 + 368432 3 @@ -14161,7 +14254,7 @@ 2 5 - 88867 + 88868 5 @@ -14182,7 +14275,7 @@ 1 2 - 759543 + 759544 2 @@ -14197,7 +14290,7 @@ 11 2029 - 22216 + 22217 @@ -14213,7 +14306,7 @@ 1 2 - 1225174 + 1225175 2 @@ -14228,7 +14321,7 @@ 4 6 - 136541 + 136542 6 @@ -14249,7 +14342,7 @@ 1 2 - 1402910 + 1402911 2 @@ -14259,7 +14352,7 @@ 3 5 - 143021 + 143022 5 @@ -14280,7 +14373,7 @@ 1 2 - 1589440 + 1589442 2 @@ -14306,7 +14399,7 @@ 1 2 - 1246002 + 1246004 2 @@ -14342,7 +14435,7 @@ 1 2 - 2947454 + 2947457 2 @@ -14368,7 +14461,7 @@ 1 2 - 3014105 + 3014108 2 @@ -14394,7 +14487,7 @@ 1 2 - 3193692 + 3193695 2 @@ -14415,7 +14508,7 @@ 1 2 - 3231646 + 3231649 2 @@ -14430,11 +14523,11 @@ fun_def - 1932415 + 1932417 id - 1932415 + 1932417 @@ -14463,11 +14556,11 @@ fun_decl_specifiers - 2890060 + 2890063 id - 1683400 + 1683401 name @@ -14485,12 +14578,12 @@ 1 2 - 495253 + 495254 2 3 - 1169632 + 1169633 3 @@ -14667,26 +14760,26 @@ fun_decl_empty_throws - 1926861 + 1926863 fun_decl - 1926861 + 1926863 fun_decl_noexcept - 61185 + 61184 fun_decl - 61185 + 61184 constant - 61080 + 61079 @@ -14700,7 +14793,7 @@ 1 2 - 61185 + 61184 @@ -14716,7 +14809,7 @@ 1 2 - 60976 + 60975 2 @@ -14731,11 +14824,11 @@ fun_decl_empty_noexcept - 873868 + 873869 fun_decl - 873868 + 873869 @@ -14840,11 +14933,11 @@ param_decl_bind - 7337161 + 7337168 id - 7337161 + 7337168 index @@ -14852,7 +14945,7 @@ fun_decl - 4202714 + 4202718 @@ -14866,7 +14959,7 @@ 1 2 - 7337161 + 7337168 @@ -14882,7 +14975,7 @@ 1 2 - 7337161 + 7337168 @@ -15060,17 +15153,17 @@ 1 2 - 2355464 + 2355466 2 3 - 1054381 + 1054382 3 4 - 498493 + 498494 4 @@ -15091,17 +15184,17 @@ 1 2 - 2355464 + 2355466 2 3 - 1054381 + 1054382 3 4 - 498493 + 498494 4 @@ -15116,19 +15209,19 @@ var_decls - 8458657 + 8458665 id - 8391080 + 8391088 variable - 7384372 + 7384380 type_id - 2376755 + 2376757 name @@ -15136,7 +15229,7 @@ location - 5278849 + 5278855 @@ -15150,7 +15243,7 @@ 1 2 - 8391080 + 8391088 @@ -15166,7 +15259,7 @@ 1 2 - 8323503 + 8323511 2 @@ -15187,7 +15280,7 @@ 1 2 - 8391080 + 8391088 @@ -15203,7 +15296,7 @@ 1 2 - 8391080 + 8391088 @@ -15219,17 +15312,17 @@ 1 2 - 6536424 + 6536430 2 3 - 695669 + 695670 3 7 - 152278 + 152279 @@ -15245,7 +15338,7 @@ 1 2 - 7214042 + 7214049 2 @@ -15266,7 +15359,7 @@ 1 2 - 7269122 + 7269129 2 @@ -15287,7 +15380,7 @@ 1 2 - 6840519 + 6840526 2 @@ -15308,12 +15401,12 @@ 1 2 - 1466784 + 1466785 2 3 - 507750 + 507751 3 @@ -15344,12 +15437,12 @@ 1 2 - 1599160 + 1599162 2 3 - 483219 + 483220 3 @@ -15375,7 +15468,7 @@ 1 2 - 1873170 + 1873172 2 @@ -15401,12 +15494,12 @@ 1 2 - 1700988 + 1700990 2 3 - 400368 + 400369 3 @@ -15478,7 +15571,7 @@ 1 2 - 365654 + 365655 2 @@ -15601,7 +15694,7 @@ 1 2 - 4462838 + 4462842 2 @@ -15627,7 +15720,7 @@ 1 2 - 4860429 + 4860434 2 @@ -15653,12 +15746,12 @@ 1 2 - 4935875 + 4935879 2 1529 - 342974 + 342975 @@ -15674,7 +15767,7 @@ 1 2 - 5274684 + 5274689 2 @@ -15689,11 +15782,11 @@ var_def - 4018035 + 4018039 id - 4018035 + 4018039 @@ -15769,19 +15862,19 @@ type_decls - 3240440 + 3240444 id - 3240440 + 3240444 type_id - 3190452 + 3190455 location - 3161755 + 3161758 @@ -15795,7 +15888,7 @@ 1 2 - 3240440 + 3240444 @@ -15811,7 +15904,7 @@ 1 2 - 3240440 + 3240444 @@ -15827,7 +15920,7 @@ 1 2 - 3149258 + 3149261 2 @@ -15848,7 +15941,7 @@ 1 2 - 3149258 + 3149261 2 @@ -15869,7 +15962,7 @@ 1 2 - 3121487 + 3121490 2 @@ -15890,7 +15983,7 @@ 1 2 - 3121487 + 3121490 2 @@ -15905,33 +15998,33 @@ type_def - 2627159 + 2627161 id - 2627159 + 2627161 type_decl_top - 743806 + 743807 type_decl - 743806 + 743807 namespace_decls - 307432 + 307431 id - 307432 + 307431 namespace_id @@ -15939,11 +16032,11 @@ location - 307432 + 307431 bodylocation - 307432 + 307431 @@ -15957,7 +16050,7 @@ 1 2 - 307432 + 307431 @@ -15973,7 +16066,7 @@ 1 2 - 307432 + 307431 @@ -15989,7 +16082,7 @@ 1 2 - 307432 + 307431 @@ -16203,7 +16296,7 @@ 1 2 - 307432 + 307431 @@ -16219,7 +16312,7 @@ 1 2 - 307432 + 307431 @@ -16235,7 +16328,7 @@ 1 2 - 307432 + 307431 @@ -16251,7 +16344,7 @@ 1 2 - 307432 + 307431 @@ -16267,7 +16360,7 @@ 1 2 - 307432 + 307431 @@ -16283,7 +16376,7 @@ 1 2 - 307432 + 307431 @@ -16351,7 +16444,7 @@ 1 2 - 260123 + 260124 2 @@ -16377,7 +16470,7 @@ 1 2 - 260123 + 260124 2 @@ -16459,7 +16552,7 @@ using_container - 476668 + 476665 parent @@ -16467,7 +16560,7 @@ child - 302247 + 302245 @@ -16537,7 +16630,7 @@ 1 2 - 222928 + 222926 2 @@ -17180,15 +17273,15 @@ params - 6699348 + 6699355 id - 6536424 + 6536430 function - 3860202 + 3860206 index @@ -17196,7 +17289,7 @@ type_id - 2182819 + 2182821 @@ -17210,7 +17303,7 @@ 1 2 - 6536424 + 6536430 @@ -17226,7 +17319,7 @@ 1 2 - 6536424 + 6536430 @@ -17242,7 +17335,7 @@ 1 2 - 6413305 + 6413311 2 @@ -17263,12 +17356,12 @@ 1 2 - 2249470 + 2249472 2 3 - 945147 + 945148 3 @@ -17294,12 +17387,12 @@ 1 2 - 2249470 + 2249472 2 3 - 945147 + 945148 3 @@ -17325,7 +17418,7 @@ 1 2 - 2547085 + 2547088 2 @@ -17594,7 +17687,7 @@ 1 2 - 1485298 + 1485299 2 @@ -17625,7 +17718,7 @@ 1 2 - 1705154 + 1705155 2 @@ -17656,7 +17749,7 @@ 1 2 - 1756993 + 1756995 2 @@ -17676,11 +17769,11 @@ overrides - 160001 + 160000 new - 125162 + 125161 old @@ -17764,19 +17857,19 @@ membervariables - 1054757 + 1054731 id - 1052962 + 1052936 type_id - 327188 + 327180 name - 450876 + 450865 @@ -17790,7 +17883,7 @@ 1 2 - 1051247 + 1051221 2 @@ -17811,7 +17904,7 @@ 1 2 - 1052962 + 1052936 @@ -17827,17 +17920,17 @@ 1 2 - 242629 + 242623 2 3 - 51812 + 51811 3 10 - 25487 + 25486 10 @@ -17858,22 +17951,22 @@ 1 2 - 254834 + 254828 2 3 - 46387 + 46386 3 40 - 24570 + 24569 41 2031 - 1396 + 1395 @@ -17889,17 +17982,17 @@ 1 2 - 294840 + 294833 2 3 - 86394 + 86391 3 5 - 41122 + 41121 5 @@ -17920,12 +18013,12 @@ 1 2 - 367234 + 367225 2 3 - 51652 + 51651 3 @@ -17940,11 +18033,11 @@ globalvariables - 300716 + 301278 id - 300708 + 301270 type_id @@ -17966,7 +18059,7 @@ 1 2 - 300700 + 301262 2 @@ -17987,7 +18080,7 @@ 1 2 - 300708 + 301270 @@ -18003,27 +18096,27 @@ 1 2 - 977 + 972 2 3 - 159 + 160 3 7 - 114 + 117 7 - 77 + 68 106 - 83 - 169397 - 49 + 76 + 169440 + 50 @@ -18075,12 +18168,12 @@ 1 2 - 290989 + 290721 2 33 - 3749 + 4017 @@ -18096,12 +18189,12 @@ 1 2 - 294142 + 294139 2 12 - 596 + 599 @@ -18111,11 +18204,11 @@ localvariables - 581177 + 581167 id - 581177 + 581167 type_id @@ -18123,7 +18216,7 @@ name - 91322 + 91320 @@ -18137,7 +18230,7 @@ 1 2 - 581177 + 581167 @@ -18153,7 +18246,7 @@ 1 2 - 581177 + 581167 @@ -18174,7 +18267,7 @@ 2 3 - 5412 + 5408 3 @@ -18184,7 +18277,7 @@ 4 7 - 3405 + 3409 7 @@ -18210,7 +18303,7 @@ 1 2 - 26975 + 26970 2 @@ -18220,7 +18313,7 @@ 3 5 - 2939 + 2943 5 @@ -18246,12 +18339,12 @@ 1 2 - 57519 + 57518 2 3 - 14407 + 14406 3 @@ -18282,7 +18375,7 @@ 1 2 - 77145 + 77144 2 @@ -18302,11 +18395,11 @@ autoderivation - 149355 + 149352 var - 149355 + 149352 derivation_type @@ -18324,7 +18417,7 @@ 1 2 - 149355 + 149352 @@ -18428,11 +18521,11 @@ enumconstants - 241273 + 241267 id - 241273 + 241267 parent @@ -18448,11 +18541,11 @@ name - 240994 + 240987 location - 221210 + 221204 @@ -18466,7 +18559,7 @@ 1 2 - 241273 + 241267 @@ -18482,7 +18575,7 @@ 1 2 - 241273 + 241267 @@ -18498,7 +18591,7 @@ 1 2 - 241273 + 241267 @@ -18514,7 +18607,7 @@ 1 2 - 241273 + 241267 @@ -18530,7 +18623,7 @@ 1 2 - 241273 + 241267 @@ -18765,7 +18858,7 @@ 2 3 - 4188 + 4187 3 @@ -18790,7 +18883,7 @@ 7 8 - 1396 + 1395 8 @@ -18831,7 +18924,7 @@ 3 4 - 1755 + 1754 4 @@ -18887,7 +18980,7 @@ 3 4 - 1755 + 1754 4 @@ -18959,7 +19052,7 @@ 3 4 - 1755 + 1754 4 @@ -19015,7 +19108,7 @@ 3 4 - 1755 + 1754 4 @@ -19141,7 +19234,7 @@ 1 2 - 240714 + 240708 2 @@ -19162,7 +19255,7 @@ 1 2 - 240714 + 240708 2 @@ -19183,7 +19276,7 @@ 1 2 - 240994 + 240987 @@ -19199,7 +19292,7 @@ 1 2 - 240994 + 240987 @@ -19215,7 +19308,7 @@ 1 2 - 240714 + 240708 2 @@ -19236,7 +19329,7 @@ 1 2 - 220452 + 220446 2 @@ -19257,7 +19350,7 @@ 1 2 - 221210 + 221204 @@ -19273,7 +19366,7 @@ 1 2 - 220452 + 220446 2 @@ -19294,7 +19387,7 @@ 1 2 - 221210 + 221204 @@ -19310,7 +19403,7 @@ 1 2 - 220452 + 220446 2 @@ -20037,15 +20130,15 @@ derivedtypes - 4324907 + 4324912 id - 4324907 + 4324912 name - 2161065 + 2161067 kind @@ -20053,7 +20146,7 @@ type_id - 2666964 + 2666967 @@ -20067,7 +20160,7 @@ 1 2 - 4324907 + 4324912 @@ -20083,7 +20176,7 @@ 1 2 - 4324907 + 4324912 @@ -20099,7 +20192,7 @@ 1 2 - 4324907 + 4324912 @@ -20115,7 +20208,7 @@ 1 2 - 1901404 + 1901406 2 @@ -20141,7 +20234,7 @@ 1 2 - 2160139 + 2160141 2 @@ -20162,7 +20255,7 @@ 1 2 - 1901404 + 1901406 2 @@ -20311,12 +20404,12 @@ 1 2 - 1649148 + 1649150 2 3 - 558201 + 558202 3 @@ -20342,7 +20435,7 @@ 1 2 - 1660257 + 1660258 2 @@ -20373,12 +20466,12 @@ 1 2 - 1653314 + 1653316 2 3 - 561904 + 561905 3 @@ -20388,7 +20481,7 @@ 4 6 - 98587 + 98588 @@ -20398,11 +20491,11 @@ pointerishsize - 3208041 + 3208044 id - 3208041 + 3208044 size @@ -20424,7 +20517,7 @@ 1 2 - 3208041 + 3208044 @@ -20440,7 +20533,7 @@ 1 2 - 3208041 + 3208044 @@ -20850,15 +20943,15 @@ typedefbase - 1722225 + 1722214 id - 1722225 + 1722214 type_id - 809049 + 809043 @@ -20872,7 +20965,7 @@ 1 2 - 1722225 + 1722214 @@ -20888,7 +20981,7 @@ 1 2 - 629268 + 629264 2 @@ -20903,7 +20996,7 @@ 6 5437 - 31435 + 31434 @@ -21199,15 +21292,15 @@ usertypes - 5230250 + 5230255 id - 5230250 + 5230255 name - 1349682 + 1349683 kind @@ -21225,7 +21318,7 @@ 1 2 - 5230250 + 5230255 @@ -21241,7 +21334,7 @@ 1 2 - 5230250 + 5230255 @@ -21257,7 +21350,7 @@ 1 2 - 980787 + 980788 2 @@ -21293,7 +21386,7 @@ 1 2 - 1209437 + 1209438 2 @@ -21445,11 +21538,11 @@ usertypesize - 1711634 + 1711635 id - 1711634 + 1711635 size @@ -21471,7 +21564,7 @@ 1 2 - 1711634 + 1711635 @@ -21487,7 +21580,7 @@ 1 2 - 1711634 + 1711635 @@ -21662,11 +21755,11 @@ usertype_uuid - 36167 + 36166 id - 36167 + 36166 uuid @@ -21684,7 +21777,7 @@ 1 2 - 36167 + 36166 @@ -21715,15 +21808,15 @@ mangled_name - 5182113 + 5182118 id - 5182113 + 5182118 mangled_name - 1244614 + 1244615 @@ -21737,7 +21830,7 @@ 1 2 - 5182113 + 5182118 @@ -21758,7 +21851,7 @@ 2 3 - 174495 + 174496 3 @@ -21788,33 +21881,33 @@ is_pod_class - 534132 + 534129 id - 534132 + 534129 is_standard_layout_class - 1259425 + 1259426 id - 1259425 + 1259426 is_complete - 1651463 + 1651464 id - 1651463 + 1651464 @@ -21832,15 +21925,15 @@ class_instantiation - 1092104 + 1092096 to - 1090870 + 1090863 from - 70259 + 70258 @@ -21854,7 +21947,7 @@ 1 2 - 1089729 + 1089722 2 @@ -21925,11 +22018,11 @@ class_template_argument - 2918536 + 2918517 type_id - 1329545 + 1329536 index @@ -21937,7 +22030,7 @@ arg_type - 856542 + 856536 @@ -21951,22 +22044,22 @@ 1 2 - 544138 + 544134 2 3 - 404518 + 404516 3 4 - 235642 + 235641 4 7 - 121141 + 121140 7 @@ -21987,17 +22080,17 @@ 1 2 - 569833 + 569829 2 3 - 416288 + 416285 3 4 - 248830 + 248828 4 @@ -22110,12 +22203,12 @@ 1 2 - 533452 + 533449 2 3 - 179089 + 179088 3 @@ -22125,7 +22218,7 @@ 4 10 - 64334 + 64333 10 @@ -22146,7 +22239,7 @@ 1 2 - 755723 + 755718 2 @@ -22166,7 +22259,7 @@ class_template_argument_value - 494790 + 494791 type_id @@ -22178,7 +22271,7 @@ arg_value - 494790 + 494791 @@ -22311,7 +22404,7 @@ 1 2 - 494790 + 494791 @@ -22327,7 +22420,7 @@ 1 2 - 494790 + 494791 @@ -22385,19 +22478,19 @@ type_mentions - 4022510 + 4022409 id - 4022510 + 4022409 type_id - 197876 + 197871 location - 3989045 + 3988945 kind @@ -22415,7 +22508,7 @@ 1 2 - 4022510 + 4022409 @@ -22431,7 +22524,7 @@ 1 2 - 4022510 + 4022409 @@ -22447,7 +22540,7 @@ 1 2 - 4022510 + 4022409 @@ -22463,12 +22556,12 @@ 1 2 - 97442 + 97440 2 3 - 21698 + 21697 3 @@ -22483,7 +22576,7 @@ 5 7 - 14359 + 14358 7 @@ -22498,7 +22591,7 @@ 27 8555 - 14399 + 14398 @@ -22514,12 +22607,12 @@ 1 2 - 97442 + 97440 2 3 - 21698 + 21697 3 @@ -22534,7 +22627,7 @@ 5 7 - 14359 + 14358 7 @@ -22549,7 +22642,7 @@ 27 8555 - 14399 + 14398 @@ -22565,7 +22658,7 @@ 1 2 - 197876 + 197871 @@ -22581,12 +22674,12 @@ 1 2 - 3955580 + 3955481 2 3 - 33464 + 33463 @@ -22602,12 +22695,12 @@ 1 2 - 3955580 + 3955481 2 3 - 33464 + 33463 @@ -22623,7 +22716,7 @@ 1 2 - 3989045 + 3988945 @@ -22681,22 +22774,22 @@ is_function_template - 1390876 + 1390877 id - 1390876 + 1390877 function_instantiation - 907058 + 907059 to - 907058 + 907059 from @@ -22714,7 +22807,7 @@ 1 2 - 907058 + 907059 @@ -22760,11 +22853,11 @@ function_template_argument - 2342325 + 2342327 function_id - 1319745 + 1319746 index @@ -22791,7 +22884,7 @@ 2 3 - 388305 + 388306 3 @@ -22817,12 +22910,12 @@ 1 2 - 695633 + 695634 2 3 - 393633 + 393634 3 @@ -23021,7 +23114,7 @@ 1 2 - 274830 + 274831 2 @@ -23053,7 +23146,7 @@ arg_value - 360889 + 360890 @@ -23093,7 +23186,7 @@ 2 3 - 20711 + 20712 3 @@ -23257,7 +23350,7 @@ 1 2 - 360889 + 360890 @@ -23278,15 +23371,15 @@ variable_instantiation - 168076 + 168074 to - 168076 + 168074 from - 25729 + 25728 @@ -23300,7 +23393,7 @@ 1 2 - 168076 + 168074 @@ -23316,7 +23409,7 @@ 1 2 - 14015 + 14014 2 @@ -23356,11 +23449,11 @@ variable_template_argument - 295468 + 295463 variable_id - 159709 + 159707 index @@ -23368,7 +23461,7 @@ arg_type - 165462 + 165459 @@ -23382,7 +23475,7 @@ 1 2 - 81894 + 81893 2 @@ -23392,12 +23485,12 @@ 3 4 - 18826 + 18825 4 17 - 9413 + 9412 @@ -23413,7 +23506,7 @@ 1 2 - 85555 + 85553 2 @@ -23556,12 +23649,12 @@ 1 2 - 133352 + 133350 2 3 - 18094 + 18093 3 @@ -23587,7 +23680,7 @@ 1 2 - 149564 + 149562 2 @@ -23768,11 +23861,11 @@ routinetypes - 547156 + 547157 id - 547156 + 547157 return_type @@ -23790,7 +23883,7 @@ 1 2 - 547156 + 547157 @@ -23826,7 +23919,7 @@ routinetypeargs - 975696 + 975697 routine @@ -23857,7 +23950,7 @@ 2 3 - 133301 + 133302 3 @@ -23888,7 +23981,7 @@ 1 2 - 180975 + 180976 2 @@ -24102,7 +24195,7 @@ 1 2 - 171255 + 171256 2 @@ -24311,11 +24404,11 @@ typespecifiers - 1287196 + 1287198 type_id - 1269145 + 1269146 spec_id @@ -24333,7 +24426,7 @@ 1 2 - 1251094 + 1251095 2 @@ -24399,11 +24492,11 @@ funspecifiers - 12354933 + 12354946 func_id - 3802185 + 3802189 spec_id @@ -24431,12 +24524,12 @@ 3 4 - 1147133 + 1147135 4 5 - 1556434 + 1556435 5 @@ -24557,11 +24650,11 @@ varspecifiers - 2310104 + 2310106 var_id - 1234894 + 1234895 spec_id @@ -24579,12 +24672,12 @@ 1 2 - 723903 + 723904 2 3 - 199952 + 199953 3 @@ -24655,11 +24748,11 @@ attributes - 737258 + 737246 id - 737258 + 737246 kind @@ -24675,7 +24768,7 @@ location - 483417 + 483409 @@ -24689,7 +24782,7 @@ 1 2 - 737258 + 737246 @@ -24705,7 +24798,7 @@ 1 2 - 737258 + 737246 @@ -24721,7 +24814,7 @@ 1 2 - 737258 + 737246 @@ -24737,7 +24830,7 @@ 1 2 - 737258 + 737246 @@ -25130,17 +25223,17 @@ 1 2 - 425055 + 425049 2 3 - 37443 + 37442 3 201 - 20918 + 20917 @@ -25156,7 +25249,7 @@ 1 2 - 483417 + 483409 @@ -25172,7 +25265,7 @@ 1 2 - 479129 + 479121 2 @@ -25193,7 +25286,7 @@ 1 2 - 483417 + 483409 @@ -25203,11 +25296,11 @@ attribute_args - 406848 + 406849 id - 406848 + 406849 kind @@ -25215,7 +25308,7 @@ attribute - 295763 + 295764 index @@ -25237,7 +25330,7 @@ 1 2 - 406848 + 406849 @@ -25253,7 +25346,7 @@ 1 2 - 406848 + 406849 @@ -25269,7 +25362,7 @@ 1 2 - 406848 + 406849 @@ -25285,7 +25378,7 @@ 1 2 - 406848 + 406849 @@ -25893,15 +25986,15 @@ typeattributes - 85973 + 85972 type_id - 62022 + 62021 spec_id - 85973 + 85972 @@ -25915,7 +26008,7 @@ 1 2 - 55014 + 55013 2 @@ -25941,7 +26034,7 @@ 1 2 - 85973 + 85972 @@ -25951,15 +26044,15 @@ funcattributes - 647729 + 647718 func_id - 592296 + 592286 spec_id - 647729 + 647718 @@ -25973,12 +26066,12 @@ 1 2 - 554120 + 554111 2 7 - 38175 + 38174 @@ -25994,7 +26087,7 @@ 1 2 - 647729 + 647718 @@ -26004,15 +26097,15 @@ varattributes - 371880 + 372127 var_id - 322247 + 322510 spec_id - 371880 + 372127 @@ -26026,17 +26119,17 @@ 1 2 - 273279 + 273537 2 3 - 48804 + 48807 3 - 62 - 164 + 46 + 166 @@ -26052,7 +26145,7 @@ 1 2 - 371880 + 372127 @@ -26110,15 +26203,15 @@ unspecifiedtype - 10137428 + 10137438 type_id - 10137428 + 10137438 unspecified_type_id - 6822468 + 6822474 @@ -26132,7 +26225,7 @@ 1 2 - 10137428 + 10137438 @@ -26148,17 +26241,17 @@ 1 2 - 4591048 + 4591053 2 3 - 1996752 + 1996754 3 147 - 234666 + 234667 @@ -26168,7 +26261,7 @@ member - 4925926 + 4925931 parent @@ -26180,7 +26273,7 @@ child - 4862061 + 4862066 @@ -26199,7 +26292,7 @@ 3 4 - 320347 + 320348 4 @@ -26224,7 +26317,7 @@ 15 24 - 49609 + 49610 24 @@ -26438,7 +26531,7 @@ 1 2 - 4862061 + 4862066 @@ -26454,12 +26547,12 @@ 1 2 - 4799678 + 4799682 2 8 - 62382 + 62383 @@ -26469,11 +26562,11 @@ enclosingfunction - 121348 + 121347 child - 121348 + 121347 parent @@ -26491,7 +26584,7 @@ 1 2 - 121348 + 121347 @@ -27108,11 +27201,11 @@ direct_base_offsets - 338942 + 338943 der_id - 338942 + 338943 offset @@ -27130,7 +27223,7 @@ 1 2 - 338942 + 338943 @@ -27472,11 +27565,11 @@ frienddecls - 716133 + 716134 id - 716133 + 716134 type_id @@ -27502,7 +27595,7 @@ 1 2 - 716133 + 716134 @@ -27518,7 +27611,7 @@ 1 2 - 716133 + 716134 @@ -27534,7 +27627,7 @@ 1 2 - 716133 + 716134 @@ -27853,19 +27946,19 @@ comments - 8773472 + 8773331 id - 8773472 + 8773331 contents - 3339994 + 3339940 location - 8773472 + 8773331 @@ -27879,7 +27972,7 @@ 1 2 - 8773472 + 8773331 @@ -27895,7 +27988,7 @@ 1 2 - 8773472 + 8773331 @@ -27911,12 +28004,12 @@ 1 2 - 3055507 + 3055458 2 7 - 250912 + 250908 7 @@ -27937,12 +28030,12 @@ 1 2 - 3055507 + 3055458 2 7 - 250912 + 250908 7 @@ -27963,7 +28056,7 @@ 1 2 - 8773472 + 8773331 @@ -27979,7 +28072,7 @@ 1 2 - 8773472 + 8773331 @@ -27989,15 +28082,15 @@ commentbinding - 3095104 + 3095107 id - 2450349 + 2450351 element - 3019196 + 3019199 @@ -28011,7 +28104,7 @@ 1 2 - 2369349 + 2369351 2 @@ -28032,7 +28125,7 @@ 1 2 - 2943288 + 2943291 2 @@ -28047,15 +28140,15 @@ exprconv - 7021832 + 7021834 converted - 7021832 + 7021834 conversion - 7021832 + 7021834 @@ -28069,7 +28162,7 @@ 1 2 - 7021832 + 7021834 @@ -28085,7 +28178,7 @@ 1 2 - 7021832 + 7021834 @@ -28095,22 +28188,22 @@ compgenerated - 8328197 + 8328205 id - 8328197 + 8328205 synthetic_destructor_call - 144327 + 144328 element - 111770 + 111771 i @@ -28118,7 +28211,7 @@ destructor_call - 129098 + 129099 @@ -28357,7 +28450,7 @@ 1 2 - 129098 + 129099 @@ -28436,7 +28529,7 @@ namespacembrs - 2389715 + 2389717 parentid @@ -28444,7 +28537,7 @@ memberid - 2389715 + 2389717 @@ -28524,7 +28617,7 @@ 1 2 - 2389715 + 2389717 @@ -28534,11 +28627,11 @@ exprparents - 14182785 + 14182799 expr_id - 14182785 + 14182799 child_index @@ -28546,7 +28639,7 @@ parent_id - 9437898 + 9437907 @@ -28560,7 +28653,7 @@ 1 2 - 14182785 + 14182799 @@ -28576,7 +28669,7 @@ 1 2 - 14182785 + 14182799 @@ -28694,12 +28787,12 @@ 1 2 - 5400325 + 5400330 2 3 - 3700399 + 3700403 3 @@ -28720,12 +28813,12 @@ 1 2 - 5400325 + 5400330 2 3 - 3700399 + 3700403 3 @@ -28740,11 +28833,11 @@ expr_isload - 4982130 + 4982107 expr_id - 4982130 + 4982107 @@ -28824,11 +28917,11 @@ iscall - 2951156 + 2951159 caller - 2951156 + 2951159 kind @@ -28846,7 +28939,7 @@ 1 2 - 2951156 + 2951159 @@ -28882,11 +28975,11 @@ numtemplatearguments - 396244 + 396245 expr_id - 396244 + 396245 num @@ -28904,7 +28997,7 @@ 1 2 - 396244 + 396245 @@ -29008,15 +29101,15 @@ namequalifiers - 1533107 + 1533108 id - 1533107 + 1533108 qualifiableelement - 1533107 + 1533108 qualifyingelement @@ -29038,7 +29131,7 @@ 1 2 - 1533107 + 1533108 @@ -29054,7 +29147,7 @@ 1 2 - 1533107 + 1533108 @@ -29070,7 +29163,7 @@ 1 2 - 1533107 + 1533108 @@ -29086,7 +29179,7 @@ 1 2 - 1533107 + 1533108 @@ -29102,7 +29195,7 @@ 1 2 - 1533107 + 1533108 @@ -29118,7 +29211,7 @@ 1 2 - 1533107 + 1533108 @@ -29349,15 +29442,15 @@ varbind - 6019055 + 6019061 expr - 6019055 + 6019061 var - 767246 + 767247 @@ -29371,7 +29464,7 @@ 1 2 - 6019055 + 6019061 @@ -29442,15 +29535,15 @@ funbind - 2954265 + 2954268 expr - 2951453 + 2951456 fun - 533823 + 533843 @@ -29464,7 +29557,7 @@ 1 2 - 2948641 + 2948644 2 @@ -29485,12 +29578,12 @@ 1 2 - 329747 + 329787 2 3 - 82204 + 82184 3 @@ -29937,15 +30030,15 @@ values - 10759270 + 10759479 id - 10759270 + 10759479 str - 87848 + 87846 @@ -29959,7 +30052,7 @@ 1 2 - 10759270 + 10759479 @@ -29975,7 +30068,7 @@ 1 2 - 59389 + 59388 2 @@ -29985,12 +30078,12 @@ 3 6 - 6924 + 6919 6 56 - 6612 + 6618 57 @@ -30068,15 +30161,15 @@ valuebind - 11192950 + 11193149 val - 10759270 + 10759479 expr - 11192950 + 11193149 @@ -30090,12 +30183,12 @@ 1 2 - 10348201 + 10348421 2 7 - 411068 + 411058 @@ -30111,7 +30204,7 @@ 1 2 - 11192950 + 11193149 @@ -30121,15 +30214,15 @@ fieldoffsets - 1052962 + 1052936 id - 1052962 + 1052936 byteoffset - 22655 + 22654 bitoffset @@ -30147,7 +30240,7 @@ 1 2 - 1052962 + 1052936 @@ -30163,7 +30256,7 @@ 1 2 - 1052962 + 1052936 @@ -30225,7 +30318,7 @@ 1 2 - 21977 + 21976 2 @@ -30322,11 +30415,11 @@ bitfield - 20918 + 20917 id - 20918 + 20917 bits @@ -30348,7 +30441,7 @@ 1 2 - 20918 + 20917 @@ -30364,7 +30457,7 @@ 1 2 - 20918 + 20917 @@ -30508,23 +30601,23 @@ initialisers - 1699581 + 1699574 init - 1699581 + 1699574 var - 722038 + 722035 expr - 1699581 + 1699574 location - 390813 + 390811 @@ -30538,7 +30631,7 @@ 1 2 - 1699581 + 1699574 @@ -30554,7 +30647,7 @@ 1 2 - 1699581 + 1699574 @@ -30570,7 +30663,7 @@ 1 2 - 1699581 + 1699574 @@ -30586,7 +30679,7 @@ 1 2 - 633767 + 633764 2 @@ -30612,7 +30705,7 @@ 1 2 - 633767 + 633764 2 @@ -30638,7 +30731,7 @@ 1 2 - 722032 + 722028 2 @@ -30659,7 +30752,7 @@ 1 2 - 1699581 + 1699574 @@ -30675,7 +30768,7 @@ 1 2 - 1699581 + 1699574 @@ -30691,7 +30784,7 @@ 1 2 - 1699581 + 1699574 @@ -30707,7 +30800,7 @@ 1 2 - 318365 + 318364 2 @@ -30738,7 +30831,7 @@ 1 2 - 341138 + 341137 2 @@ -30764,7 +30857,7 @@ 1 2 - 318365 + 318364 2 @@ -30863,11 +30956,11 @@ exprs - 18356790 + 18356808 id - 18356790 + 18356808 kind @@ -30875,7 +30968,7 @@ location - 3591749 + 3591752 @@ -30889,7 +30982,7 @@ 1 2 - 18356790 + 18356808 @@ -30905,7 +30998,7 @@ 1 2 - 18356790 + 18356808 @@ -31073,7 +31166,7 @@ 1 2 - 1941352 + 1941354 2 @@ -31114,17 +31207,17 @@ 1 2 - 2391758 + 2391761 2 3 - 875231 + 875232 3 6 - 307821 + 307822 6 @@ -31139,15 +31232,15 @@ expr_types - 18411724 + 18411742 id - 18356790 + 18356808 typeid - 881136 + 881137 value_category @@ -31165,7 +31258,7 @@ 1 2 - 18301855 + 18301873 2 @@ -31186,7 +31279,7 @@ 1 2 - 18356790 + 18356808 @@ -31207,7 +31300,7 @@ 2 3 - 172230 + 172231 3 @@ -31258,7 +31351,7 @@ 2 3 - 111869 + 111870 3 @@ -32102,7 +32195,7 @@ type_id - 19827 + 19826 @@ -32147,11 +32240,11 @@ sizeof_bind - 198889 + 198884 expr - 198889 + 198884 type_id @@ -32169,7 +32262,7 @@ 1 2 - 198889 + 198884 @@ -33273,11 +33366,11 @@ stmts - 4653233 + 4653158 id - 4653233 + 4653158 kind @@ -33285,7 +33378,7 @@ location - 2284884 + 2284848 @@ -33299,7 +33392,7 @@ 1 2 - 4653233 + 4653158 @@ -33315,7 +33408,7 @@ 1 2 - 4653233 + 4653158 @@ -33543,22 +33636,22 @@ 1 2 - 1890473 + 1890443 2 4 - 175816 + 175813 4 12 - 176025 + 176023 12 687 - 42568 + 42567 @@ -33574,12 +33667,12 @@ 1 2 - 2227673 + 2227637 2 8 - 57211 + 57210 @@ -33877,15 +33970,15 @@ constexpr_if_then - 52504 + 52503 constexpr_if_stmt - 52504 + 52503 then_id - 52504 + 52503 @@ -33899,7 +33992,7 @@ 1 2 - 52504 + 52503 @@ -33915,7 +34008,7 @@ 1 2 - 52504 + 52503 @@ -33925,15 +34018,15 @@ constexpr_if_else - 30854 + 30853 constexpr_if_stmt - 30854 + 30853 else_id - 30854 + 30853 @@ -33947,7 +34040,7 @@ 1 2 - 30854 + 30853 @@ -33963,7 +34056,7 @@ 1 2 - 30854 + 30853 @@ -34021,15 +34114,15 @@ do_body - 148628 + 148625 do_stmt - 148628 + 148625 body_id - 148628 + 148625 @@ -34043,7 +34136,7 @@ 1 2 - 148628 + 148625 @@ -34059,7 +34152,7 @@ 1 2 - 148628 + 148625 @@ -34383,15 +34476,15 @@ switch_body - 20747 + 20746 switch_stmt - 20747 + 20746 body_id - 20747 + 20746 @@ -34405,7 +34498,7 @@ 1 2 - 20747 + 20746 @@ -34421,7 +34514,7 @@ 1 2 - 20747 + 20746 @@ -34623,11 +34716,11 @@ stmtparents - 4056811 + 4056792 id - 4056811 + 4056792 index @@ -34635,7 +34728,7 @@ parent - 1721378 + 1721371 @@ -34649,7 +34742,7 @@ 1 2 - 4056811 + 4056792 @@ -34665,7 +34758,7 @@ 1 2 - 4056811 + 4056792 @@ -34803,12 +34896,12 @@ 1 2 - 988419 + 988415 2 3 - 373378 + 373376 3 @@ -34818,12 +34911,12 @@ 4 6 - 111365 + 111364 6 17 - 129977 + 129976 17 @@ -34844,12 +34937,12 @@ 1 2 - 988419 + 988415 2 3 - 373378 + 373376 3 @@ -34859,12 +34952,12 @@ 4 6 - 111365 + 111364 6 17 - 129977 + 129976 17 @@ -34890,11 +34983,11 @@ stmt_decl_bind - 585107 + 585097 stmt - 544993 + 544983 num @@ -34902,7 +34995,7 @@ decl - 585002 + 584992 @@ -34916,12 +35009,12 @@ 1 2 - 524132 + 524123 2 19 - 20861 + 20860 @@ -34937,12 +35030,12 @@ 1 2 - 524132 + 524123 2 19 - 20861 + 20860 @@ -35140,7 +35233,7 @@ 1 2 - 584964 + 584954 2 @@ -35161,7 +35254,7 @@ 1 2 - 585002 + 584992 @@ -35171,11 +35264,11 @@ stmt_decl_entry_bind - 527567 + 527557 stmt - 487755 + 487746 num @@ -35183,7 +35276,7 @@ decl_entry - 527508 + 527499 @@ -35197,7 +35290,7 @@ 1 2 - 467158 + 467150 2 @@ -35218,7 +35311,7 @@ 1 2 - 467158 + 467150 2 @@ -35421,7 +35514,7 @@ 1 2 - 527487 + 527478 3 @@ -35442,7 +35535,7 @@ 1 2 - 527508 + 527499 @@ -35452,15 +35545,15 @@ blockscope - 1414944 + 1414946 block - 1414944 + 1414946 enclosing - 1300619 + 1300621 @@ -35474,7 +35567,7 @@ 1 2 - 1414944 + 1414946 @@ -35490,7 +35583,7 @@ 1 2 - 1235820 + 1235821 2 @@ -35505,11 +35598,11 @@ jumpinfo - 254036 + 254032 id - 254036 + 254032 str @@ -35517,7 +35610,7 @@ target - 53054 + 53053 @@ -35531,7 +35624,7 @@ 1 2 - 254036 + 254032 @@ -35547,7 +35640,7 @@ 1 2 - 254036 + 254032 @@ -35568,7 +35661,7 @@ 3 4 - 4247 + 4246 4 @@ -35609,7 +35702,7 @@ 1 2 - 16720 + 16719 2 @@ -35681,7 +35774,7 @@ 1 2 - 53054 + 53053 @@ -35691,11 +35784,11 @@ preprocdirects - 4427317 + 4427246 id - 4427317 + 4427246 kind @@ -35703,7 +35796,7 @@ location - 4424807 + 4424736 @@ -35717,7 +35810,7 @@ 1 2 - 4427317 + 4427246 @@ -35733,7 +35826,7 @@ 1 2 - 4427317 + 4427246 @@ -35871,7 +35964,7 @@ 1 2 - 4424702 + 4424631 25 @@ -35892,7 +35985,7 @@ 1 2 - 4424807 + 4424736 @@ -35902,15 +35995,15 @@ preprocpair - 1419110 + 1419111 begin - 1186757 + 1186758 elseelifend - 1419110 + 1419111 @@ -35929,7 +36022,7 @@ 2 3 - 206432 + 206433 3 @@ -35950,7 +36043,7 @@ 1 2 - 1419110 + 1419111 @@ -35960,11 +36053,11 @@ preproctrue - 770651 + 770652 branch - 770651 + 770652 @@ -35982,19 +36075,19 @@ preproctext - 3569465 + 3569408 id - 3569465 + 3569408 head - 2589243 + 2589201 body - 1514470 + 1514446 @@ -36008,7 +36101,7 @@ 1 2 - 3569465 + 3569408 @@ -36024,7 +36117,7 @@ 1 2 - 3569465 + 3569408 @@ -36040,12 +36133,12 @@ 1 2 - 2442293 + 2442254 2 740 - 146949 + 146947 @@ -36061,12 +36154,12 @@ 1 2 - 2527116 + 2527075 2 5 - 62126 + 62125 @@ -36082,12 +36175,12 @@ 1 2 - 1370972 + 1370950 2 6 - 113585 + 113583 6 @@ -36108,12 +36201,12 @@ 1 2 - 1374005 + 1373983 2 7 - 113899 + 113897 7 @@ -36249,11 +36342,11 @@ link_parent - 38279611 + 38417223 element - 4843995 + 4860584 link_target @@ -36271,17 +36364,17 @@ 1 2 - 645317 + 646377 2 9 - 25334 + 25792 9 10 - 4173343 + 4188413 @@ -36300,48 +36393,48 @@ 35 - 118453 - 118454 + 118880 + 118881 35 - 118557 - 118558 + 118984 + 118985 35 - 118652 - 118653 + 119079 + 119080 35 - 118687 - 118688 + 119114 + 119115 35 - 118693 - 118694 + 119120 + 119121 35 - 118709 - 118710 + 119145 + 119146 35 - 120575 - 120576 + 121003 + 121004 35 - 125080 - 125081 + 125539 + 125540 35 - 127476 - 127477 + 127917 + 127918 35 diff --git a/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme new file mode 100644 index 00000000000..f96ad9b2da4 --- /dev/null +++ b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme @@ -0,0 +1,2136 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..625f706f2a4 --- /dev/null +++ b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/semmlecode.cpp.dbscheme @@ -0,0 +1,2190 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/upgrade.properties b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/upgrade.properties new file mode 100644 index 00000000000..db0e7e92d0e --- /dev/null +++ b/cpp/ql/lib/upgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/upgrade.properties @@ -0,0 +1,2 @@ +description: Add new builtin operations +compatibility: backwards diff --git a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql b/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql index 7361e875581..ca8d277cc91 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql +++ b/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql @@ -12,5 +12,5 @@ import cpp from Class c where c.fromSource() -select c as Class, c.getMetrics().getAfferentCoupling() as AfferentCoupling, - c.getMetrics().getEfferentSourceCoupling() as EfferentCoupling order by AfferentCoupling desc +select c as class_, c.getMetrics().getAfferentCoupling() as afferentCoupling, + c.getMetrics().getEfferentSourceCoupling() as efferentCoupling order by afferentCoupling desc diff --git a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql index 0fc6f0ba2a7..693c2961e4d 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql +++ b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql @@ -16,5 +16,5 @@ predicate hasInheritanceDepth(Class c, int d) { from int depth where hasInheritanceDepth(_, depth) -select depth as InheritanceDepth, count(Class c | hasInheritanceDepth(c, depth)) as NumberOfClasses - order by InheritanceDepth +select depth as inheritanceDepth, count(Class c | hasInheritanceDepth(c, depth)) as numberOfClasses + order by inheritanceDepth diff --git a/cpp/ql/src/Architecture/General Top-Level Information/GeneralStatistics.ql b/cpp/ql/src/Architecture/General Top-Level Information/GeneralStatistics.ql index 6f842baec42..a065e4d4823 100644 --- a/cpp/ql/src/Architecture/General Top-Level Information/GeneralStatistics.ql +++ b/cpp/ql/src/Architecture/General Top-Level Information/GeneralStatistics.ql @@ -51,4 +51,4 @@ where 100 * sum(Class c | c.fromSource() | c.getMetrics().getEfferentSourceCoupling()) / sum(Class c | c.fromSource() | c.getMetrics().getEfferentCoupling()) ).toString() + "%" -select l as Title, n as Value +select l as title, n as value diff --git a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyDependencies.ql b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyDependencies.ql index 384af9ebef8..a38cbbd9cb6 100644 --- a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyDependencies.ql +++ b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyDependencies.ql @@ -16,4 +16,4 @@ where t.fromSource() and n = t.getMetrics().getEfferentSourceCoupling() and n > 10 -select t as Class, "This class has too many dependencies (" + n.toString() + ")" +select t as class_, "This class has too many dependencies (" + n.toString() + ")" diff --git a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql index a5f46595f6c..e7d95091d3d 100644 --- a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql +++ b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql @@ -63,17 +63,17 @@ class VariableDeclarationLine extends TVariableDeclarationInfo { /** * Gets a `VariableDeclarationEntry` on this line. */ - VariableDeclarationEntry getAVDE() { vdeInfo(result, c, f, line) } + VariableDeclarationEntry getAVde() { vdeInfo(result, c, f, line) } /** * Gets the start column of the first `VariableDeclarationEntry` on this line. */ - int getStartColumn() { result = min(this.getAVDE().getLocation().getStartColumn()) } + int getStartColumn() { result = min(this.getAVde().getLocation().getStartColumn()) } /** * Gets the end column of the last `VariableDeclarationEntry` on this line. */ - int getEndColumn() { result = max(this.getAVDE().getLocation().getEndColumn()) } + int getEndColumn() { result = max(this.getAVde().getLocation().getEndColumn()) } /** * Gets the rank of this `VariableDeclarationLine` in its file and class @@ -134,13 +134,13 @@ class VariableDeclarationGroup extends VariableDeclarationLine { count(VariableDeclarationLine l | l = this.getProximateNext*() | - l.getAVDE().getVariable().getName() + l.getAVde().getVariable().getName() ) } override string toString() { this.getCount() = 1 and - result = "declaration of " + this.getAVDE().getVariable().getName() + result = "declaration of " + this.getAVde().getVariable().getName() or this.getCount() > 1 and result = "group of " + this.getCount() + " fields here" diff --git a/cpp/ql/src/Architecture/Refactoring Opportunities/ComplexFunctions.ql b/cpp/ql/src/Architecture/Refactoring Opportunities/ComplexFunctions.ql index 5fe0585131c..ff4ce9fbda1 100644 --- a/cpp/ql/src/Architecture/Refactoring Opportunities/ComplexFunctions.ql +++ b/cpp/ql/src/Architecture/Refactoring Opportunities/ComplexFunctions.ql @@ -17,4 +17,4 @@ where n = f.getMetrics().getNumberOfCalls() and n > 99 and not f.isMultiplyDefined() -select f as Function, "This function makes too many calls (" + n.toString() + ")" +select f as function, "This function makes too many calls (" + n.toString() + ")" diff --git a/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql b/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql index 97481bc8b03..be175660bd9 100644 --- a/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql +++ b/cpp/ql/src/Best Practices/BlockWithTooManyStatements.ql @@ -29,7 +29,4 @@ where n = strictcount(ComplexStmt s | s = b.getAStmt()) and n > 3 and complexStmt = b.getAStmt() -select b, - "Block with too many statements (" + n.toString() + - " complex statements in the block). Complex statements at: $@", complexStmt, - complexStmt.toString() +select b, "Block with too many statements (" + n.toString() + " complex statements in the block)." diff --git a/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql b/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql index 6e434c85c95..055fbf29f7c 100644 --- a/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql +++ b/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql @@ -110,4 +110,4 @@ where emptyBlock(s, eb) and not emptyBlockContainsNonchild(eb) and not lineComment(eb) -select eb, "Empty block without comment" +select eb, "Empty block without comment." diff --git a/cpp/ql/src/Best Practices/UseOfGoto.ql b/cpp/ql/src/Best Practices/UseOfGoto.ql index a1dcddc0123..26d72d69a0a 100644 --- a/cpp/ql/src/Best Practices/UseOfGoto.ql +++ b/cpp/ql/src/Best Practices/UseOfGoto.ql @@ -16,7 +16,7 @@ import cpp class JumpTarget extends Stmt { JumpTarget() { exists(GotoStmt g | g.getTarget() = this) } - FunctionDeclarationEntry getFDE() { result.getBlock() = this.getParentStmt+() } + FunctionDeclarationEntry getFde() { result.getBlock() = this.getParentStmt+() } predicate isForward() { exists(GotoStmt g | g.getTarget() = this | @@ -33,8 +33,8 @@ class JumpTarget extends Stmt { from FunctionDeclarationEntry fde, int nforward, int nbackward where - nforward = strictcount(JumpTarget t | t.getFDE() = fde and t.isForward()) and - nbackward = strictcount(JumpTarget t | t.getFDE() = fde and t.isBackward()) and + nforward = strictcount(JumpTarget t | t.getFde() = fde and t.isForward()) and + nbackward = strictcount(JumpTarget t | t.getFde() = fde and t.isBackward()) and nforward != 1 and nbackward != 1 select fde, diff --git a/cpp/ql/src/Critical/MissingCheckScanf.cpp b/cpp/ql/src/Critical/MissingCheckScanf.cpp new file mode 100644 index 00000000000..c4700a67e47 --- /dev/null +++ b/cpp/ql/src/Critical/MissingCheckScanf.cpp @@ -0,0 +1,17 @@ +{ + int i, j, r; + + r = scanf("%d %d", &i, &j); + + use(i); // BAD: i is not guarded + + if (r >= 1) { + use(i); // GOOD: i is guarded correctly + use(j); // BAD: j is guarded incorrectly + } + + if (r != 2) + return; + + use(j); // GOOD: j is guarded correctly +} diff --git a/cpp/ql/src/Critical/MissingCheckScanf.qhelp b/cpp/ql/src/Critical/MissingCheckScanf.qhelp new file mode 100644 index 00000000000..162c94cf9f8 --- /dev/null +++ b/cpp/ql/src/Critical/MissingCheckScanf.qhelp @@ -0,0 +1,51 @@ + + + + + +

+This query finds calls of scanf-like functions with missing or +improper return-value checking. +

+

+Specifically, the query flags uses of variables that may have been modified by +scanf and subsequently are used without being guarded by a correct +return-value check. A proper check is one that ensures that the corresponding +scanf has returned (at least) a certain minimum constant. +

+

+Functions in the scanf family return either EOF (a negative value) +in case of IO failure, or the number of items successfully read from the +input. Consequently, a simple check that the return value is truthy (nonzero) +is not enough. +

+ +This query has medium precision because, in the current implementation, it +takes a strict stance on unguarded uses of output variables, and flags them +as problematic even if they have already been initialized. + +
+ + +

+Ensure that all subsequent uses of scanf output arguments occur in a +branch of an if statement (or similar), in which it is known that the +corresponding scanf call has in fact read all possible items from its +input. This can be done by comparing the return value to a numerical constant. +

+
+ + +

This example shows different ways of guarding a scanf output: +

+ +
+ + +
  • SEI CERT C++ Coding Standard: ERR62-CPP. Detect errors when converting a string to a number.
  • +
  • SEI CERT C Coding Standard: ERR33-C. Detect and handle standard library errors.
  • +
  • cppreference.com: scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s.
  • +
    +
    diff --git a/cpp/ql/src/Critical/MissingCheckScanf.ql b/cpp/ql/src/Critical/MissingCheckScanf.ql new file mode 100644 index 00000000000..ff859e27735 --- /dev/null +++ b/cpp/ql/src/Critical/MissingCheckScanf.ql @@ -0,0 +1,122 @@ +/** + * @name Missing return-value check for a 'scanf'-like function + * @description Failing to check that a call to 'scanf' actually writes to an + * output variable can lead to unexpected behavior at reading time. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision medium + * @id cpp/missing-check-scanf + * @tags security + * correctness + * external/cwe/cwe-252 + * external/cwe/cwe-253 + */ + +import cpp +import semmle.code.cpp.commons.Scanf +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.ir.IR +import semmle.code.cpp.ir.ValueNumbering + +/** An expression appearing as an output argument to a `scanf`-like call */ +class ScanfOutput extends Expr { + ScanfFunctionCall call; + int varargIndex; + Instruction instr; + ValueNumber valNum; + + ScanfOutput() { + this = call.getOutputArgument(varargIndex).getFullyConverted() and + instr.getConvertedResultExpression() = this and + valueNumber(instr) = valNum + } + + ScanfFunctionCall getCall() { result = call } + + /** + * Returns the smallest possible `scanf` return value that would indicate + * success in writing this output argument. + */ + int getMinimumGuardConstant() { + result = + varargIndex + 1 - + count(ScanfFormatLiteral f, int n | + // Special case: %n writes to an argument without reading any input. + // It does not increase the count returned by `scanf`. + n <= varargIndex and f.getUse() = call and f.getConversionChar(n) = "n" + ) + } + + predicate hasGuardedAccess(Access e, boolean isGuarded) { + e = this.getAnAccess() and + if + exists(int value, int minGuard | minGuard = this.getMinimumGuardConstant() | + e.getBasicBlock() = blockGuardedBy(value, "==", call) and minGuard <= value + or + e.getBasicBlock() = blockGuardedBy(value, "<", call) and minGuard - 1 <= value + or + e.getBasicBlock() = blockGuardedBy(value, "<=", call) and minGuard <= value + ) + then isGuarded = true + else isGuarded = false + } + + /** + * Get a subsequent access of the same underlying storage, + * but before it gets reset or reused in another `scanf` call. + */ + Access getAnAccess() { + exists(Instruction dst | + this.bigStep() = dst and + dst.getAst() = result and + valueNumber(dst) = valNum + ) + } + + private Instruction bigStep() { + result = this.smallStep(instr) + or + exists(Instruction i | i = this.bigStep() | result = this.smallStep(i)) + } + + private Instruction smallStep(Instruction i) { + instr.getASuccessor*() = i and + i.getASuccessor() = result and + not this.isBarrier(result) + } + + private predicate isBarrier(Instruction i) { + valueNumber(i) = valNum and + exists(Expr e | i.getAst() = e | + i = any(StoreInstruction s).getDestinationAddress() + or + [e, e.getParent().(AddressOfExpr)] instanceof ScanfOutput + ) + } +} + +/** Returns a block guarded by the assertion of `value op call` */ +BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) { + exists(GuardCondition g, Expr left, Expr right | + right = g.getAChild() and + value = left.getValue().toInt() and + DataFlow::localExprFlow(call, right) + | + g.ensuresEq(left, right, 0, result, true) and op = "==" + or + g.ensuresLt(left, right, 0, result, true) and op = "<" + or + g.ensuresLt(left, right, 1, result, true) and op = "<=" + ) +} + +from ScanfOutput output, ScanfFunctionCall call, Access access +where + output.getCall() = call and + output.hasGuardedAccess(access, false) +select access, + "$@ is read here, but may not have been written. " + + "It should be guarded by a check that the $@ returns at least " + + output.getMinimumGuardConstant() + ".", access, access.toString(), call, call.toString() diff --git a/cpp/ql/src/Documentation/CommentedOutCode.ql b/cpp/ql/src/Documentation/CommentedOutCode.ql index 89411738178..1fe70ac4c94 100644 --- a/cpp/ql/src/Documentation/CommentedOutCode.ql +++ b/cpp/ql/src/Documentation/CommentedOutCode.ql @@ -12,4 +12,4 @@ import CommentedOutCode from CommentedOutCode comment -select comment, "This comment appears to contain commented-out code" +select comment, "This comment appears to contain commented-out code." diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/BitwiseSignCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/BitwiseSignCheck.ql index fe1b2640058..dd27e4b7aee 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/BitwiseSignCheck.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/BitwiseSignCheck.ql @@ -1,7 +1,6 @@ /** * @name Sign check of bitwise operation - * @description Checking the sign of a bitwise operation often has surprising - * edge cases. + * @description Checking the sign of the result of a bitwise operation may yield unexpected results. * @kind problem * @problem.severity warning * @precision high @@ -26,4 +25,4 @@ where forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and // exception for cases involving macros not e.isAffectedByMacro() -select e, "Potential unsafe sign check of a bitwise operation." +select e, "Potentially unsafe sign check of a bitwise operation." diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/FloatComparison.ql b/cpp/ql/src/Likely Bugs/Arithmetic/FloatComparison.ql index 5233f567fa5..5a2180bfaf3 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/FloatComparison.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/FloatComparison.ql @@ -21,4 +21,4 @@ where FloatingPointType and not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison -select ro, "Equality test on floating point values may not behave as expected." +select ro, "Equality checks on floating point values can yield unexpected results." diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql b/cpp/ql/src/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql index 554937127c0..86e419f22ac 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql @@ -13,10 +13,11 @@ import cpp -from EnumSwitch es, float missing, float total +from EnumSwitch es, float missing, float total, EnumConstant case where not es.hasDefaultCase() and missing = count(es.getAMissingCase()) and total = missing + count(es.getASwitchCase()) and - missing / total < 0.3 -select es, "Switch statement is missing case for " + es.getAMissingCase().getName() + missing / total < 0.3 and + case = es.getAMissingCase() +select es, "Switch statement does not have a case for $@.", case, case.getName() diff --git a/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.ql index 2d1440813f4..a468ce4a46d 100644 --- a/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.ql @@ -14,4 +14,4 @@ where n.fromSource() and c = n.getMetrics().getAbstractness() and c > 0.2 -select n as Namespace, c as Abstractness order by Abstractness desc +select n as namespace, c as abstractness order by abstractness desc diff --git a/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.ql index c71f654f275..cd60b46594a 100644 --- a/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.ql @@ -13,4 +13,4 @@ where n.fromSource() and c = n.getMetrics().getAbstractness() and c = 0 -select n as Namespace, c as Abstractness order by Abstractness desc +select n as namespace, c as abstractness order by abstractness desc diff --git a/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.ql index 89dae1a3404..4b89e3710ce 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.ql @@ -15,4 +15,4 @@ where n.fromSource() and c = n.getMetrics().getAfferentCoupling() and c > 20 -select n as Namespace, c as AfferentCoupling order by AfferentCoupling desc +select n as namespace, c as afferentCoupling order by afferentCoupling desc diff --git a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.ql index ce5553749d2..f97bb3e4f5c 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.ql @@ -15,4 +15,4 @@ where n.fromSource() and c = n.getMetrics().getDistanceFromMain() and c > 0.7 -select n as Namespace, c as DistanceFromMainline order by DistanceFromMainline desc +select n as namespace, c as distanceFromMainline order by distanceFromMainline desc diff --git a/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.ql index 1de659f1384..35ebe468be6 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.ql @@ -15,4 +15,4 @@ where n.fromSource() and c = n.getMetrics().getEfferentCoupling() and c > 20 -select n as Namespace, c as EfferentCoupling order by EfferentCoupling desc +select n as namespace, c as efferentCoupling order by efferentCoupling desc diff --git a/cpp/ql/src/Metrics/Namespaces/StableNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/StableNamespaces.ql index 3fd17ee4066..37c1b698c56 100644 --- a/cpp/ql/src/Metrics/Namespaces/StableNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/StableNamespaces.ql @@ -14,4 +14,4 @@ where n.fromSource() and c = n.getMetrics().getInstability() and c < 0.2 -select n as Namespace, c as Instability order by Instability desc +select n as namespace, c as instability order by instability desc diff --git a/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.ql b/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.ql index 8e150d62f03..8dbaa5f1cc7 100644 --- a/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.ql +++ b/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.ql @@ -14,4 +14,4 @@ where n.fromSource() and c = n.getMetrics().getInstability() and c > 0.8 -select n as Package, c as Instability order by Instability desc +select n as package, c as instability order by instability desc diff --git a/cpp/ql/src/Microsoft/CallWithNullSAL.ql b/cpp/ql/src/Microsoft/CallWithNullSAL.ql index d5c74547c3e..dcf47fcbf5d 100644 --- a/cpp/ql/src/Microsoft/CallWithNullSAL.ql +++ b/cpp/ql/src/Microsoft/CallWithNullSAL.ql @@ -13,7 +13,7 @@ import SAL from Parameter p, Call c, Expr arg where - any(SALNotNull a).getDeclaration() = p and + any(SalNotNull a).getDeclaration() = p and c.getTarget() = p.getFunction() and arg = c.getArgument(p.getIndex()) and nullValue(arg) diff --git a/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql b/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql index bf52b2bb615..8202b2d4b05 100644 --- a/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql +++ b/cpp/ql/src/Microsoft/IgnoreReturnValueSAL.ql @@ -18,7 +18,7 @@ from Function f, FunctionCall call where call.getTarget() = f and call instanceof ExprInVoidContext and - any(SALCheckReturn a).getDeclaration() = f and + any(SalCheckReturn a).getDeclaration() = f and not getOptions().okToIgnoreReturnValue(call) select call, "Return value of $@ discarded although a SAL annotation " + "requires inspecting it.", f, f.getName() diff --git a/cpp/ql/src/Microsoft/InconsistentSAL.ql b/cpp/ql/src/Microsoft/InconsistentSAL.ql index e5965e62b49..fcda9e40f45 100644 --- a/cpp/ql/src/Microsoft/InconsistentSAL.ql +++ b/cpp/ql/src/Microsoft/InconsistentSAL.ql @@ -11,7 +11,7 @@ import SAL /** Holds if `e` has SAL annotation `name`. */ predicate hasAnnotation(DeclarationEntry e, string name) { - exists(SALAnnotation a | + exists(SalAnnotation a | a.getMacro().getName() = name and a.getDeclarationEntry() = e ) @@ -21,7 +21,7 @@ predicate hasAnnotation(DeclarationEntry e, string name) { predicate inheritsDeclAnnotations(DeclarationEntry e) { // Is directly annotated e.isDefinition() and - exists(SALAnnotation a | a.getMacro().getName() = "_Use_decl_annotations_" | + exists(SalAnnotation a | a.getMacro().getName() = "_Use_decl_annotations_" | a.getDeclarationEntry() = e ) or diff --git a/cpp/ql/src/Microsoft/SAL.qll b/cpp/ql/src/Microsoft/SAL.qll index 46fedbb5d80..99102755b2d 100644 --- a/cpp/ql/src/Microsoft/SAL.qll +++ b/cpp/ql/src/Microsoft/SAL.qll @@ -8,8 +8,8 @@ import cpp /** * A SAL macro defined in `sal.h` or a similar header file. */ -class SALMacro extends Macro { - SALMacro() { +class SalMacro extends Macro { + SalMacro() { this.getFile().getBaseName() = ["sal.h", "specstrings_strict.h", "specstrings.h", "w32p.h", "minwindef.h"] and ( @@ -22,15 +22,18 @@ class SALMacro extends Macro { } } +/** DEPRECATED: Alias for SalMacro */ +deprecated class SALMacro = SalMacro; + pragma[noinline] private predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) } /** * An invocation of a SAL macro (excluding invocations inside other macros). */ -class SALAnnotation extends MacroInvocation { - SALAnnotation() { - this.getMacro() instanceof SALMacro and +class SalAnnotation extends MacroInvocation { + SalAnnotation() { + this.getMacro() instanceof SalMacro and isTopLevelMacroAccess(this) } @@ -47,23 +50,29 @@ class SALAnnotation extends MacroInvocation { } } +/** DEPRECATED: Alias for SalAnnotation */ +deprecated class SALAnnotation = SalAnnotation; + /** * A SAL macro indicating that the return value of a function should always be * checked. */ -class SALCheckReturn extends SALAnnotation { - SALCheckReturn() { - this.getMacro().(SALMacro).getName() = ["_Check_return_", "_Must_inspect_result_"] +class SalCheckReturn extends SalAnnotation { + SalCheckReturn() { + this.getMacro().(SalMacro).getName() = ["_Check_return_", "_Must_inspect_result_"] } } +/** DEPRECATED: Alias for SalCheckReturn */ +deprecated class SALCheckReturn = SalCheckReturn; + /** * A SAL macro indicating that a pointer variable or return value should not be * `NULL`. */ -class SALNotNull extends SALAnnotation { - SALNotNull() { - exists(SALMacro m | m = this.getMacro() | +class SalNotNull extends SalAnnotation { + SalNotNull() { + exists(SalMacro m | m = this.getMacro() | not m.getName().matches("%\\_opt\\_%") and ( m.getName().matches("_In%") or @@ -80,12 +89,15 @@ class SALNotNull extends SALAnnotation { } } +/** DEPRECATED: Alias for SalNotNull */ +deprecated class SALNotNull = SalNotNull; + /** * A SAL macro indicating that a value may be `NULL`. */ -class SALMaybeNull extends SALAnnotation { - SALMaybeNull() { - exists(SALMacro m | m = this.getMacro() | +class SalMaybeNull extends SalAnnotation { + SalMaybeNull() { + exists(SalMacro m | m = this.getMacro() | m.getName().matches("%\\_opt\\_%") or m.getName().matches("\\_Ret_maybenull\\_%") or m.getName() = "_Result_nullonfailure_" @@ -93,14 +105,17 @@ class SALMaybeNull extends SALAnnotation { } } +/** DEPRECATED: Alias for SalMaybeNull */ +deprecated class SALMaybeNull = SalMaybeNull; + /** * A parameter annotated by one or more SAL annotations. */ -class SALParameter extends Parameter { +class SalParameter extends Parameter { /** One of this parameter's annotations. */ - SALAnnotation a; + SalAnnotation a; - SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) } + SalParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) } predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") } @@ -109,14 +124,17 @@ class SALParameter extends Parameter { predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") } } +/** DEPRECATED: Alias for SalParameter */ +deprecated class SALParameter = SalParameter; + /////////////////////////////////////////////////////////////////////////////// // Implementation details /** * Holds if `a` annotates the declaration entry `d` and * its start position is the `idx`th position in `file` that holds a SAL element. */ -private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) { - annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx) +private predicate annotatesAt(SalAnnotation a, DeclarationEntry d, File file, int idx) { + annotatesAtPosition(a.(SalElement).getStartPosition(), d, file, idx) } /** @@ -127,12 +145,12 @@ private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, in // For performance reasons, do not mention the annotation itself here, // but compute with positions instead. This performs better on databases // with many annotations at the same position. -private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File file, int idx) { +private predicate annotatesAtPosition(SalPosition pos, DeclarationEntry d, File file, int idx) { pos = salRelevantPositionAt(file, idx) and salAnnotationPos(pos) and ( // Base case: `pos` right before `d` - d.(SALElement).getStartPosition() = salRelevantPositionAt(file, idx + 1) + d.(SalElement).getStartPosition() = salRelevantPositionAt(file, idx + 1) or // Recursive case: `pos` right before some annotation on `d` annotatesAtPosition(_, d, file, idx + 1) @@ -143,10 +161,10 @@ private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File * A SAL element, that is, a SAL annotation or a declaration entry * that may have SAL annotations. */ -library class SALElement extends Element { - SALElement() { - containsSALAnnotation(this.(DeclarationEntry).getFile()) or - this instanceof SALAnnotation +library class SalElement extends Element { + SalElement() { + containsSalAnnotation(this.(DeclarationEntry).getFile()) or + this instanceof SalAnnotation } predicate hasStartPosition(File file, int line, int col) { @@ -173,25 +191,28 @@ library class SALElement extends Element { ) } - SALPosition getStartPosition() { + SalPosition getStartPosition() { exists(File file, int line, int col | this.hasStartPosition(file, line, col) and - result = MkSALPosition(file, line, col) + result = MkSalPosition(file, line, col) ) } } +/** DEPRECATED: Alias for SalElement */ +deprecated class SALElement = SalElement; + /** Holds if `file` contains a SAL annotation. */ pragma[noinline] -private predicate containsSALAnnotation(File file) { any(SALAnnotation a).getFile() = file } +private predicate containsSalAnnotation(File file) { any(SalAnnotation a).getFile() = file } /** * A source-file position of a `SALElement`. Unlike location, this denotes a * point in the file rather than a range. */ -private newtype SALPosition = - MkSALPosition(File file, int line, int col) { - exists(SALElement e | +private newtype SalPosition = + MkSalPosition(File file, int line, int col) { + exists(SalElement e | e.hasStartPosition(file, line, col) or e.hasEndPosition(file, line, col) @@ -200,18 +221,18 @@ private newtype SALPosition = /** Holds if `pos` is the start position of a SAL annotation. */ pragma[noinline] -private predicate salAnnotationPos(SALPosition pos) { - any(SALAnnotation a).(SALElement).getStartPosition() = pos +private predicate salAnnotationPos(SalPosition pos) { + any(SalAnnotation a).(SalElement).getStartPosition() = pos } /** * Gets the `idx`th position in `file` that holds a SAL element, * ordering positions lexicographically by their start line and start column. */ -private SALPosition salRelevantPositionAt(File file, int idx) { +private SalPosition salRelevantPositionAt(File file, int idx) { result = - rank[idx](SALPosition pos, int line, int col | - pos = MkSALPosition(file, line, col) + rank[idx](SalPosition pos, int line, int col | + pos = MkSalPosition(file, line, col) | pos order by line, col ) diff --git a/cpp/ql/src/PointsTo/TaintedFormatStrings.ql b/cpp/ql/src/PointsTo/TaintedFormatStrings.ql index 1b671697573..929833f52a0 100644 --- a/cpp/ql/src/PointsTo/TaintedFormatStrings.ql +++ b/cpp/ql/src/PointsTo/TaintedFormatStrings.ql @@ -119,4 +119,4 @@ predicate potentialViolation(InputBuffer source, FormatBuffer dest) { from InputBuffer source, FormatBuffer dest where potentialViolation(source, dest) -select dest.getFile() as File, dest as FormatString +select dest.getFile() as file, dest as formatString diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql index 9a08bbd64a6..c062039d930 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql +++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql @@ -24,7 +24,7 @@ where if e = DefinitionInSnapshot() then defined = "" else - if e = SuggestiveSALAnnotation() + if e = SuggestiveSalAnnotation() then defined = "externally defined (SAL) " else defined = "externally defined (CSV) " ) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 29f519163cc..a5def46dd60 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -149,7 +149,7 @@ newtype Evidence = * The function is externally defined, but the parameter has an `_out` SAL annotation which * suggests that it is initialized in the function. */ - SuggestiveSALAnnotation() or + SuggestiveSalAnnotation() or /** * We have been given a CSV file which indicates this parameter is conditionally initialized. */ @@ -198,8 +198,8 @@ class InitializationFunction extends Function { or // If we have no definition, we look at SAL annotations not this.hasDefinition() and - this.getParameter(i).(SALParameter).isOut() and - evidence = SuggestiveSALAnnotation() + this.getParameter(i).(SalParameter).isOut() and + evidence = SuggestiveSalAnnotation() or // We have some external information that this function conditionally initializes not this.hasDefinition() and diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index da17913dec5..abd1773afd8 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -19,8 +19,8 @@ import DataFlow::PathGraph /** * A configuration for tracking XML objects and their states. */ -class XXEConfiguration extends DataFlow::Configuration { - XXEConfiguration() { this = "XXEConfiguration" } +class XxeConfiguration extends DataFlow::Configuration { + XxeConfiguration() { this = "XXEConfiguration" } override predicate isSource(DataFlow::Node node, string flowstate) { any(XmlLibrary l).configurationSource(node, flowstate) @@ -45,7 +45,7 @@ class XXEConfiguration extends DataFlow::Configuration { } } -from XXEConfiguration conf, DataFlow::PathNode source, DataFlow::PathNode sink +from XxeConfiguration conf, DataFlow::PathNode source, DataFlow::PathNode sink where conf.hasFlowPath(source, sink) select sink, source, sink, "This $@ is not configured to prevent an XML external entity (XXE) attack.", source, "XML parser" diff --git a/cpp/ql/src/change-notes/2022-08-23-alert-messages.md b/cpp/ql/src/change-notes/2022-08-23-alert-messages.md new file mode 100644 index 00000000000..22f4c5c6682 --- /dev/null +++ b/cpp/ql/src/change-notes/2022-08-23-alert-messages.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The alert message of many queries have been changed to make the message consistent with other languages. \ No newline at end of file diff --git a/cpp/ql/src/change-notes/2022-08-24-missing-check-scanf.md b/cpp/ql/src/change-notes/2022-08-24-missing-check-scanf.md new file mode 100644 index 00000000000..d8e5384422e --- /dev/null +++ b/cpp/ql/src/change-notes/2022-08-24-missing-check-scanf.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new medium-precision query, `cpp/missing-check-scanf`, which detects `scanf` output variables that are used without a proper return-value check to see that they were actually written. A variation of this query was originally contributed as an [experimental query by @ihsinme](https://github.com/github/codeql/pull/8246). diff --git a/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql b/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql new file mode 100644 index 00000000000..7b163f5c05c --- /dev/null +++ b/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql @@ -0,0 +1,51 @@ +import cpp +import experimental.semmle.code.cpp.dataflow.ProductFlow +import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis +import experimental.semmle.code.cpp.rangeanalysis.Bound +import experimental.semmle.code.cpp.semantic.SemanticExprSpecific +import semmle.code.cpp.ir.IR +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.models.interfaces.Allocation +import semmle.code.cpp.ir.IRConfiguration + +predicate bounded(Instruction i, Bound b, int delta, boolean upper) { + // TODO: reason + semBounded(getSemanticExpr(i), b, delta, upper, _) +} + +class ArraySizeConfiguration extends ProductFlow::Configuration { + ArraySizeConfiguration() { this = "ArraySizeConfiguration" } + + override predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) { + exists(GVN sizeGvn | + source1.asConvertedExpr().(AllocationExpr).getSizeExpr() = sizeGvn.getAnExpr() and + source2.asConvertedExpr() = sizeGvn.getAnExpr() + ) + } + + override predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) { + exists(PointerAddInstruction pai, Instruction index, Bound b, int delta | + pai.getRight() = index and + pai.getLeft() = sink1.asInstruction() and + bounded(index, b, delta, true) and + sink2.asInstruction() = b.getInstruction() and + ( + delta = 0 and + exists(DataFlow::Node paiNode, DataFlow::Node derefNode | + DataFlow::localFlow(paiNode, derefNode) and + paiNode.asInstruction() = pai and + derefNode.asOperand() instanceof AddressOperand + ) + or + delta >= 1 + ) + ) + } +} + +from + ArraySizeConfiguration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2, + DataFlow::PathNode sink1, DataFlow2::PathNode sink2 +where conf.hasFlowPath(source1, source2, sink1, sink2) +// TODO: pull delta out and display it +select source1, source2, sink1, sink2 diff --git a/cpp/ql/src/experimental/Likely Bugs/OverrunWriteProductFlow.ql b/cpp/ql/src/experimental/Likely Bugs/OverrunWriteProductFlow.ql new file mode 100644 index 00000000000..07e78db7344 --- /dev/null +++ b/cpp/ql/src/experimental/Likely Bugs/OverrunWriteProductFlow.ql @@ -0,0 +1,34 @@ +import cpp +import experimental.semmle.code.cpp.dataflow.ProductFlow +import semmle.code.cpp.ir.IR +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.models.interfaces.Allocation +import semmle.code.cpp.models.interfaces.ArrayFunction + +class StringSizeConfiguration extends ProductFlow::Configuration { + StringSizeConfiguration() { this = "StringSizeConfiguration" } + + override predicate isSourcePair(DataFlow::Node bufSource, DataFlow::Node sizeSource) { + exists( + GVN sizeGvn // TODO: use-use flow instead of GVN + | + bufSource.asConvertedExpr().(AllocationExpr).getSizeExpr() = sizeGvn.getAnExpr() and + sizeSource.asConvertedExpr() = sizeGvn.getAnExpr() + ) + } + + override predicate isSinkPair(DataFlow::Node bufSink, DataFlow::Node sizeSink) { + exists(CallInstruction c, int bufIndex, int sizeIndex | + c.getStaticCallTarget().(ArrayFunction).hasArrayWithVariableSize(bufIndex, sizeIndex) and + c.getArgument(bufIndex) = bufSink.asInstruction() and + c.getArgument(sizeIndex) = sizeSink.asInstruction() + ) + } +} + +// we don't actually check correctness yet. Right now the query just finds relevant source/sink pairs. +from + StringSizeConfiguration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2, + DataFlow::PathNode sink1, DataFlow2::PathNode sink2 +where conf.hasFlowPath(source1, source2, sink1, sink2) +select source1, source2, sink1, sink2 diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.cpp new file mode 100644 index 00000000000..0ad0635ae40 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.cpp @@ -0,0 +1,26 @@ +void *malloc(unsigned); +unsigned get_size(); +void write_data(const unsigned char*, const unsigned char*); + +int main(int argc, char* argv[]) { + unsigned size = get_size(); + + { + unsigned char *begin = (unsigned char*)malloc(size); + if(!begin) return -1; + + unsigned char* end = begin + size; + write_data(begin, end); + *end = '\0'; // BAD: Out-of-bounds write + } + + { + unsigned char *begin = (unsigned char*)malloc(size); + if(!begin) return -1; + + unsigned char* end = begin + size; + write_data(begin, end); + *(end - 1) = '\0'; // GOOD: writing to the last byte + } + +} \ No newline at end of file diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.qhelp new file mode 100644 index 00000000000..4f590659112 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.qhelp @@ -0,0 +1,31 @@ + + + +

    The program performs an out-of-bounds read or write operation. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code.

    + +
    + + +

    Ensure that pointer dereferences are properly guarded to ensure that they cannot be used to read or write past the end of the allocation.

    + +
    + +

    The first example allocates a buffer of size size and creates a local variable that stores the location that is one byte past the end of the allocation. +This local variable is then dereferenced which results in an out-of-bounds write. +The second example subtracts one from the end variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.

    + + +
    + + +
  • CERT C Coding Standard: +ARR30-C. Do not form or use out-of-bounds pointers or array subscripts.
  • +
  • +OWASP: +Buffer Overflow. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql new file mode 100644 index 00000000000..05327263386 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -0,0 +1,360 @@ +/** + * @name Invalid pointer dereference + * @description Dereferencing a pointer that points past it allocation is undefined behavior + * and may lead to security vulnerabilities. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cpp/invalid-pointer-deref + * @tags reliability + * security + * external/cwe/cwe-119 + * external/cwe/cwe-125 + * external/cwe/cwe-193 + * external/cwe/cwe-787 + */ + +import cpp +import experimental.semmle.code.cpp.dataflow.ProductFlow +import experimental.semmle.code.cpp.ir.dataflow.DataFlow3 +import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis +import experimental.semmle.code.cpp.semantic.SemanticBound +import experimental.semmle.code.cpp.semantic.SemanticExprSpecific +import semmle.code.cpp.ir.IR + +pragma[nomagic] +Instruction getABoundIn(SemBound b, IRFunction func) { + result = b.getExpr(0) and + result.getEnclosingIRFunction() = func +} + +/** + * Holds if `i <= b + delta`. + */ +pragma[nomagic] +predicate bounded(Instruction i, Instruction b, int delta) { + exists(SemBound bound, IRFunction func | + semBounded(getSemanticExpr(i), bound, delta, true, _) and + b = getABoundIn(bound, func) and + i.getEnclosingIRFunction() = func + ) +} + +/** + * Holds if the combination of `n` and `state` represents an appropriate + * source for the expression `e` suitable for use-use flow. + */ +private predicate hasSizeImpl(Expr e, DataFlow::Node n, string state) { + // The simple case: If the size is a variable access with no qualifier we can just use the + // dataflow node for that expression and no state. + exists(VariableAccess va | + va = e and + not va instanceof FieldAccess and + n.asConvertedExpr() = va.getFullyConverted() and + state = "0" + ) + or + // If the size is a choice between two expressions we allow both to be nodes representing the size. + exists(ConditionalExpr cond | cond = e | hasSizeImpl([cond.getThen(), cond.getElse()], n, state)) + or + // If the size is an expression plus a constant, we pick the dataflow node of the expression and + // remember the constant in the state. + exists(Expr const, Expr nonconst | + e.(AddExpr).hasOperands(const, nonconst) and + state = const.getValue() and + hasSizeImpl(nonconst, n, _) + ) + or + exists(Expr const, Expr nonconst | + e.(SubExpr).hasOperands(const, nonconst) and + state = "-" + const.getValue() and + hasSizeImpl(nonconst, n, _) + ) +} + +/** + * Holds if `(n, state)` pair represents the source of flow for the size + * expression associated with `alloc`. + */ +predicate hasSize(AllocationExpr alloc, DataFlow::Node n, string state) { + hasSizeImpl(alloc.getSizeExpr(), n, state) +} + +/** + * A product-flow configuration for flow from an (allocation, size) pair to a + * pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`. + * + * The goal of this query is to find patterns such as: + * ```cpp + * 1. char* begin = (char*)malloc(size); + * 2. char* end = begin + size; + * 3. for(int *p = begin; p <= end; p++) { + * 4. use(*p); + * 5. } + * ``` + * + * We do this by splitting the task up into two configurations: + * 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and + * 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3). + * + * Finally, the range-analysis library will find a load from (or store to) an address that + * is non-strictly upper-bounded by `end` (which in this case is `*p`). + */ +class AllocToInvalidPointerConf extends ProductFlow::Configuration { + AllocToInvalidPointerConf() { this = "AllocToInvalidPointerConf" } + + override predicate isSourcePair( + DataFlow::Node source1, string state1, DataFlow::Node source2, string state2 + ) { + // In the case of an allocation like + // ```cpp + // malloc(size + 1); + // ``` + // we use `state2` to remember that there was an offset (in this case an offset of `1`) added + // to the size of the allocation. This state is then checked in `isSinkPair`. + state1 = "" and + hasSize(source1.asConvertedExpr(), source2, state2) + } + + override predicate isSinkPair( + DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2, + DataFlow::FlowState state2 + ) { + state1 = "" and + // We check that the delta computed by the range analysis matches the + // state value that we set in `isSourcePair`. + exists(int delta | + isSinkImpl(_, sink1, sink2, delta) and + state2 = delta.toString() + ) + } +} + +pragma[nomagic] +predicate pointerAddInstructionHasOperands( + PointerAddInstruction pai, Instruction left, Instruction right +) { + pai.getLeft() = left and + pai.getRight() = right +} + +/** + * Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the + * left operand of the pointer-arithmetic operation. + * + * For example in, + * ```cpp + * char* end = p + (size + 1); + * ``` + * We will have: + * - `pai` is `p + (size + 1)`, + * - `sink1` is `p` + * - `sink2` is `size` + * - `delta` is `1`. + */ +pragma[nomagic] +predicate pointerAddInstructionHasBounds( + PointerAddInstruction pai, DataFlow::Node sink1, Instruction sink2, int delta +) { + exists(Instruction right | + pointerAddInstructionHasOperands(pai, sink1.asInstruction(), right) and + bounded(right, sink2, delta) + ) +} + +/** + * Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the + * left operand of the pointer-arithmetic operation. + * + * See `pointerAddInstructionHasBounds` for an example. + */ +predicate isSinkImpl( + PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta +) { + pointerAddInstructionHasBounds(pai, sink1, sink2.asInstruction(), delta) +} + +/** + * Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that + * writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that + * reads from an address that non-strictly upper-bounds `sink`. + */ +predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) { + exists(AddressOperand addr, int delta | + bounded(addr.getDef(), sink.asInstruction(), delta) and + delta >= 0 and + i.getAnOperand() = addr + | + i instanceof StoreInstruction and + operation = "write" + or + i instanceof LoadInstruction and + operation = "read" + ) +} + +/** + * A configuration to track flow from a pointer-arithmetic operation found + * by `AllocToInvalidPointerConf` to a dereference of the pointer. + */ +class InvalidPointerToDerefConf extends DataFlow3::Configuration { + InvalidPointerToDerefConf() { this = "InvalidPointerToDerefConf" } + + override predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) } + + override predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) } +} + +/** + * Holds if `pai` is a pointer-arithmetic operation and `source` is a dataflow node with a + * pointer-value that is non-strictly upper bounded by `pai + delta`. + * + * For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such + * as `(p + size) + 1` and `source` is the node representing `(p + size) + 1`. In this + * case `delta` is 1. + */ +predicate invalidPointerToDerefSource( + PointerArithmeticInstruction pai, DataFlow::Node source, int delta +) { + exists(ProductFlow::Configuration conf, DataFlow::PathNode p, DataFlow::Node sink1 | + p.getNode() = sink1 and + conf.hasFlowPath(_, _, p, _) and + isSinkImpl(pai, sink1, _, _) and + bounded(source.asInstruction(), pai, delta) and + delta >= 0 + ) +} + +newtype TMergedPathNode = + // The path nodes computed by the first projection of `AllocToInvalidPointerConf` + TPathNode1(DataFlow::PathNode p) or + // The path nodes computed by `InvalidPointerToDerefConf` + TPathNode3(DataFlow3::PathNode p) or + // The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`. + // This one is needed because the sink identified by `InvalidPointerToDerefConf` is the + // pointer, but we want to raise an alert at the dereference. + TPathNodeSink(Instruction i) { + exists(DataFlow::Node n | + any(InvalidPointerToDerefConf conf).hasFlow(_, n) and + isInvalidPointerDerefSink(n, i, _) + ) + } + +class MergedPathNode extends TMergedPathNode { + string toString() { none() } + + final DataFlow::PathNode asPathNode1() { this = TPathNode1(result) } + + final DataFlow3::PathNode asPathNode3() { this = TPathNode3(result) } + + final Instruction asSinkNode() { this = TPathNodeSink(result) } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } +} + +class PathNode1 extends MergedPathNode, TPathNode1 { + override string toString() { + exists(DataFlow::PathNode p | + this = TPathNode1(p) and + result = p.toString() + ) + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +class PathNode3 extends MergedPathNode, TPathNode3 { + override string toString() { + exists(DataFlow3::PathNode p | + this = TPathNode3(p) and + result = p.toString() + ) + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.asPathNode3().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +class PathSinkNode extends MergedPathNode, TPathNodeSink { + override string toString() { + exists(Instruction i | + this = TPathNodeSink(i) and + result = i.toString() + ) + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.asSinkNode() + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +query predicate edges(MergedPathNode node1, MergedPathNode node2) { + node1.asPathNode1().getASuccessor() = node2.asPathNode1() + or + joinOn1(_, node1.asPathNode1(), node2.asPathNode3()) + or + node1.asPathNode3().getASuccessor() = node2.asPathNode3() + or + joinOn2(node1.asPathNode3(), node2.asSinkNode(), _) +} + +/** + * Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source + * of `InvalidPointerToDerefConf`, and they are connected through `pai`. + */ +predicate joinOn1(PointerArithmeticInstruction pai, DataFlow::PathNode p1, DataFlow3::PathNode p2) { + isSinkImpl(pai, p1.getNode(), _, _) and + invalidPointerToDerefSource(pai, p2.getNode(), _) +} + +/** + * Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction + * that dereferences `p1`. The string `operation` describes whether the `i` is + * a `StoreInstruction` or `LoadInstruction`. + */ +predicate joinOn2(DataFlow3::PathNode p1, Instruction i, string operation) { + isInvalidPointerDerefSink(p1.getNode(), i, operation) +} + +predicate hasFlowPath( + MergedPathNode source1, MergedPathNode sink, DataFlow3::PathNode source3, + PointerArithmeticInstruction pai, string operation +) { + exists( + AllocToInvalidPointerConf conf1, InvalidPointerToDerefConf conf2, DataFlow3::PathNode sink3, + DataFlow::PathNode sink1 + | + conf1.hasFlowPath(source1.asPathNode1(), _, sink1, _) and + joinOn1(pai, sink1, source3) and + conf2.hasFlowPath(source3, sink3) and + joinOn2(sink3, sink.asSinkNode(), operation) + ) +} + +from + MergedPathNode source, MergedPathNode sink, int k, string kstr, DataFlow3::PathNode source3, + PointerArithmeticInstruction pai, string operation, Expr offset, DataFlow::Node n +where + hasFlowPath(source, sink, source3, pai, operation) and + invalidPointerToDerefSource(pai, source3.getNode(), k) and + offset = pai.getRight().getUnconvertedResultExpression() and + n = source.asPathNode1().getNode() and + if k = 0 then kstr = "" else kstr = " + " + k +select sink, source, sink, + "This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr + + ".", n, n.toString(), offset, offset.toString() diff --git a/cpp/ql/src/jsf/3.02 Code Size and Complexity/AV Rule 2.ql b/cpp/ql/src/jsf/3.02 Code Size and Complexity/AV Rule 2.ql index 0420b9c3984..d3f7ac9adb7 100644 --- a/cpp/ql/src/jsf/3.02 Code Size and Complexity/AV Rule 2.ql +++ b/cpp/ql/src/jsf/3.02 Code Size and Complexity/AV Rule 2.ql @@ -16,17 +16,17 @@ import cpp // pointers. This will obviously not catch code that uses inline assembly to achieve // self-modification, nor will it spot the use of OS mechanisms to write into process // memory (such as WriteProcessMemory under Windows). -predicate maybeSMCConversion(Type t1, Type t2) { +predicate maybeSmcConversion(Type t1, Type t2) { t1 instanceof FunctionPointerType and t2 instanceof PointerType and not t2 instanceof FunctionPointerType and not t2 instanceof VoidPointerType or - maybeSMCConversion(t2, t1) + maybeSmcConversion(t2, t1) } from Expr e where e.fromSource() and - maybeSMCConversion(e.getUnderlyingType(), e.getActualType()) + maybeSmcConversion(e.getUnderlyingType(), e.getActualType()) select e, "AV Rule 2: There shall not be any self-modifying code." diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected index 78ff3edde3d..106313c8707 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected @@ -1,32 +1,34 @@ -| test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 | -| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:20:10:20:10 | Store: x | test.cpp:14:15:14:15 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:20:10:20:10 | Store: x | test.cpp:14:22:14:22 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cpp:15:7:15:11 | test.cpp:15:7:15:11 | +| test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | ValueNumberBound | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 | +| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:20:10:20:10 | Store: x | test.cpp:14:15:14:15 | ValueNumberBound | -2 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:20:10:20:10 | Store: x | test.cpp:14:22:14:22 | ValueNumberBound | -2 | false | CompareLT: ... < ... | test.cpp:15:7:15:11 | test.cpp:15:7:15:11 | | test.cpp:27:10:27:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:27:10:27:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 | +| test.cpp:27:10:27:10 | Load: i | test.cpp:24:15:24:15 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 | | test.cpp:30:10:30:10 | Load: i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 | -| test.cpp:30:10:30:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:30:10:30:10 | Load: i | test.cpp:26:14:26:14 | Phi: i | 0 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 | +| test.cpp:30:10:30:10 | Load: i | test.cpp:24:15:24:15 | ValueNumberBound | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:30:10:30:10 | Load: i | test.cpp:26:14:26:14 | ValueNumberBound | 0 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 | | test.cpp:33:10:33:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:33:10:33:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 | -| test.cpp:33:10:33:10 | Load: i | test.cpp:26:14:26:14 | Phi: i | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 | -| test.cpp:33:10:33:10 | Load: i | test.cpp:29:14:29:14 | Phi: i | 0 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 | -| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:16:38:20 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:28:38:30 | InitializeParameter: end | -1 | true | CompareLT: ... < ... | test.cpp:39:10:39:20 | test.cpp:39:10:39:20 | -| test.cpp:49:12:49:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 | -| test.cpp:49:12:49:12 | Load: x | test.cpp:46:29:46:29 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 | -| test.cpp:54:12:54:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 | -| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 | -| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:39:61:51 | Convert: (char *)... | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 | -| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 3 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | -| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:32:61:35 | Phi: iter | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | -| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:39:61:51 | Convert: (char *)... | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | +| test.cpp:33:10:33:10 | Load: i | test.cpp:24:15:24:15 | ValueNumberBound | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 | +| test.cpp:33:10:33:10 | Load: i | test.cpp:26:14:26:14 | ValueNumberBound | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 | +| test.cpp:33:10:33:10 | Load: i | test.cpp:29:14:29:14 | ValueNumberBound | 0 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 | +| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:16:38:20 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:28:38:30 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:39:10:39:20 | test.cpp:39:10:39:20 | +| test.cpp:49:12:49:12 | Load: x | test.cpp:46:22:46:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 | +| test.cpp:49:12:49:12 | Load: x | test.cpp:46:29:46:29 | ValueNumberBound | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 | +| test.cpp:54:12:54:12 | Load: x | test.cpp:46:22:46:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 | +| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 | +| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:39:61:51 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 | +| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:48:61:50 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 | +| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 3 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | +| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:32:61:35 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | +| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:39:61:51 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | +| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:48:61:50 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 | | test.cpp:77:12:77:12 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:77:12:77:12 | Load: i | test.cpp:72:15:72:15 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 | -| test.cpp:77:12:77:12 | Load: i | test.cpp:72:22:72:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 | +| test.cpp:77:12:77:12 | Load: i | test.cpp:72:15:72:15 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 | +| test.cpp:77:12:77:12 | Load: i | test.cpp:72:22:72:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 | | test.cpp:85:10:85:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareGT: ... > ... | test.cpp:84:7:84:11 | test.cpp:84:7:84:11 | | test.cpp:87:10:87:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareGT: ... > ... | test.cpp:84:7:84:11 | test.cpp:84:7:84:11 | | test.cpp:90:10:90:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareGE: ... >= ... | test.cpp:89:7:89:12 | test.cpp:89:7:89:12 | @@ -35,32 +37,32 @@ | test.cpp:97:10:97:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 | | test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 | | test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 | -| test.cpp:117:10:117:10 | Load: i | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:116:7:116:11 | test.cpp:116:7:116:11 | +| test.cpp:117:10:117:10 | Load: i | test.cpp:114:3:114:6 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:116:7:116:11 | test.cpp:116:7:116:11 | | test.cpp:130:10:130:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | | test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 | -| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | false | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | -| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | -| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | -| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | -| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | -| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | -| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | -| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | false | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | -| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | -| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | -| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 | -| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 | -| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | -| test.cpp:177:10:177:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 1 | false | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | -| test.cpp:179:10:179:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | -| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 | -| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | -| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 | -| test.cpp:194:8:194:8 | Load: l | test.cpp:191:16:191:16 | InitializeParameter: i | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:194:8:194:8 | Load: l | test.cpp:191:16:191:16 | InitializeParameter: i | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | -| test.cpp:200:10:200:10 | Load: i | test.cpp:198:25:198:25 | InitializeParameter: l | -1 | true | CompareLT: ... < ... | test.cpp:199:7:199:11 | test.cpp:199:7:199:11 | -| test.cpp:203:11:203:11 | Load: i | test.cpp:198:25:198:25 | InitializeParameter: l | -3 | true | CompareLT: ... < ... | test.cpp:202:7:202:15 | test.cpp:202:7:202:15 | -| test.cpp:209:10:209:10 | Load: x | test.cpp:207:24:207:24 | InitializeParameter: y | -3 | true | CompareLT: ... < ... | test.cpp:208:7:208:15 | test.cpp:208:7:208:15 | +| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | ValueNumberBound | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 | +| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | ValueNumberBound | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | ValueNumberBound | 1 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | false | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | +| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | +| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | +| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -2 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 | +| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | +| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | +| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -2 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | +| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | false | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | +| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | +| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | -1 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 | +| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 | +| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 | +| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | ValueNumberBound | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 | +| test.cpp:177:10:177:10 | Load: i | test.cpp:175:23:175:23 | ValueNumberBound | 1 | false | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | +| test.cpp:179:10:179:10 | Load: i | test.cpp:175:23:175:23 | ValueNumberBound | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | +| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 | +| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | ValueNumberBound | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 | +| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | ValueNumberBound | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 | +| test.cpp:194:8:194:8 | Load: l | test.cpp:191:16:191:16 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:194:8:194:8 | Load: l | test.cpp:191:16:191:16 | ValueNumberBound | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | +| test.cpp:200:10:200:10 | Load: i | test.cpp:198:25:198:25 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:199:7:199:11 | test.cpp:199:7:199:11 | +| test.cpp:203:11:203:11 | Load: i | test.cpp:198:25:198:25 | ValueNumberBound | -3 | true | CompareLT: ... < ... | test.cpp:202:7:202:15 | test.cpp:202:7:202:15 | +| test.cpp:209:10:209:10 | Load: x | test.cpp:207:24:207:24 | ValueNumberBound | -3 | true | CompareLT: ... < ... | test.cpp:208:7:208:15 | test.cpp:208:7:208:15 | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected new file mode 100644 index 00000000000..dedb1d72a38 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected @@ -0,0 +1,2 @@ +| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:26:18:26:23 | Load | test.cpp:26:31:26:39 | Convert | +| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:30:18:30:23 | Load | test.cpp:30:31:30:39 | Convert | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.qlref new file mode 100644 index 00000000000..21ced45de5d --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.qlref @@ -0,0 +1 @@ +experimental/Likely Bugs/OverrunWriteProductFlow.ql \ No newline at end of file diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/test.cpp new file mode 100644 index 00000000000..670b43f672e --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/test.cpp @@ -0,0 +1,37 @@ + +typedef unsigned long long size_t; +int sprintf(char *s, const char *format, ...); +int snprintf(char *s, size_t n, const char *format, ...); +int scanf(const char *format, ...); +int sscanf(const char *s, const char *format, ...); +char *malloc(size_t size); +char *strncpy(char *dst, const char *src, size_t n); + +typedef struct +{ + char *string; + int size; +} string_t; + +string_t *mk_string_t(int size) { + string_t *str = (string_t *) malloc(sizeof(string_t)); + str->size = size; + str->string = malloc(size); + return str; +} + +void test1(int size, char *buf) { + string_t *str = mk_string_t(size); + + strncpy(str->string, buf, str->size); +} + +void strncpy_wrapper(string_t *str, char *buf) { + strncpy(str->string, buf, str->size); +} + +void test2(int size, char *buf) { + string_t *str = mk_string_t(size); + strncpy_wrapper(str, buf); +} + diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected new file mode 100644 index 00000000000..8b82181b9f7 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected @@ -0,0 +1,20 @@ +| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | Load | test.cpp:5:25:5:28 | Load | +| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load | +| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | Load | test.cpp:5:25:5:28 | Load | +| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load | +| test.cpp:4:17:4:22 | call to malloc | test.cpp:9:26:9:29 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load | +| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:35:13:35:13 | Load | test.cpp:30:29:30:32 | Load | +| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:35:13:35:13 | Load | test.cpp:34:30:34:33 | Load | +| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:45:13:45:13 | Load | test.cpp:40:29:40:32 | Load | +| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:45:13:45:13 | Load | test.cpp:44:30:44:33 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:5:55:19 | Store | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:5:55:19 | Store | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:16:55:19 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:56:20:56:23 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:58:29:58:32 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:62:30:62:33 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:58:29:58:32 | size | test.cpp:63:13:63:13 | Load | test.cpp:58:29:58:32 | Load | +| test.cpp:56:13:56:18 | call to malloc | test.cpp:62:30:62:33 | size | test.cpp:63:13:63:13 | Load | test.cpp:62:30:62:33 | Load | +| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:83:14:83:14 | Load | test.cpp:82:31:82:34 | Load | +| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | Load | test.cpp:88:30:88:33 | Load | +| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | Load | test.cpp:92:31:92:34 | Load | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.qlref new file mode 100644 index 00000000000..8186dd0721b --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.qlref @@ -0,0 +1 @@ +experimental/Likely Bugs/ArrayAccessProductFlow.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp new file mode 100644 index 00000000000..f35379db3e4 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp @@ -0,0 +1,110 @@ +char *malloc(int size); + +void test1(int size) { + char *arr = malloc(size); + for (int i = 0; i < size; i++) { + arr[i] = 0; // GOOD + } + + for (int i = 0; i <= size; i++) { + arr[i] = i; // BAD + } +} + +typedef struct { + int size; + char *p; +} array_t; + +array_t mk_array(int size) { + array_t arr; + arr.size = size; + arr.p = malloc(size); + + return arr; +} + +void test2(int size) { + array_t arr = mk_array(size); + + for (int i = 0; i < arr.size; i++) { + arr.p[i] = 0; // GOOD + } + + for (int i = 0; i <= arr.size; i++) { + arr.p[i] = i; // BAD + } +} + +void test3_callee(array_t arr) { + for (int i = 0; i < arr.size; i++) { + arr.p[i] = 0; // GOOD + } + + for (int i = 0; i <= arr.size; i++) { + arr.p[i] = i; // BAD + } +} + +void test3(int size) { + test3_callee(mk_array(size)); +} + +void test4(int size) { + array_t arr; + arr.size = size; + arr.p = malloc(size); + + for (int i = 0; i < arr.size; i++) { + arr.p[i] = 0; // GOOD + } + + for (int i = 0; i <= arr.size; i++) { + arr.p[i] = i; // BAD + } +} + +array_t *mk_array_p(int size) { + array_t *arr = (array_t*) malloc(sizeof(array_t)); + arr->size = size; + arr->p = malloc(size); + + return arr; +} + +void test5(int size) { + array_t *arr = mk_array_p(size); + + for (int i = 0; i < arr->size; i++) { + arr->p[i] = 0; // GOOD + } + + for (int i = 0; i <= arr->size; i++) { + arr->p[i] = i; // BAD + } +} + +void test6_callee(array_t *arr) { + for (int i = 0; i < arr->size; i++) { + arr->p[i] = 0; // GOOD + } + + for (int i = 0; i <= arr->size; i++) { + arr->p[i] = i; // BAD + } +} + +void test6(int size) { + test6_callee(mk_array_p(size)); +} + +void test7(int size) { + char *arr = malloc(size); + for (char *p = arr; p < arr + size; p++) { + *p = 0; // GOOD + } + + for (char *p = arr; p <= arr + size; p++) { + *p = 0; // BAD [NOT DETECTED] + } +} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected new file mode 100644 index 00000000000..494713b124b --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -0,0 +1,627 @@ +edges +| test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... | +| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:5:15:5:22 | Store | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:5:15:5:22 | Store | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:6:15:6:15 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:7:16:7:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:5:15:5:22 | Store | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:5:15:5:22 | Store | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:8:16:8:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:9:16:9:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:10:16:10:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:11:16:11:16 | Load | +| test.cpp:5:15:5:22 | Store | test.cpp:12:16:12:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:6:15:6:15 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:6:15:6:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:7:16:7:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:6:15:6:15 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:6:15:6:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:6:15:6:15 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:7:16:7:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:7:16:7:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:7:16:7:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:7:16:7:16 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:8:16:8:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:7:16:7:16 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:8:16:8:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:8:16:8:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:8:16:8:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:8:16:8:16 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:9:16:9:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:9:16:9:16 | Load | test.cpp:10:16:10:16 | Load | +| test.cpp:9:16:9:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:9:16:9:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:9:16:9:16 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:10:16:10:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:10:16:10:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:10:16:10:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:10:16:10:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:10:16:10:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:10:16:10:16 | Load | test.cpp:11:16:11:16 | Load | +| test.cpp:10:16:10:16 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:11:16:11:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:11:16:11:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load | +| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load | +| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... | +| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... | +| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | +| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | +| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | +| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | +| test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... | +| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:29:15:29:28 | Store | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:29:15:29:28 | Store | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:30:15:30:15 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:31:16:31:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:29:15:29:28 | Store | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:29:15:29:28 | Store | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:32:16:32:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:33:16:33:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:34:16:34:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:35:16:35:16 | Load | +| test.cpp:29:15:29:28 | Store | test.cpp:36:16:36:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:30:15:30:15 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:30:15:30:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:31:16:31:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:30:15:30:15 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:30:15:30:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:30:15:30:15 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:31:16:31:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:31:16:31:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:31:16:31:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:31:16:31:16 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:32:16:32:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:31:16:31:16 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:32:16:32:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:32:16:32:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:32:16:32:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:32:16:32:16 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:33:16:33:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:33:16:33:16 | Load | test.cpp:34:16:34:16 | Load | +| test.cpp:33:16:33:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:33:16:33:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:33:16:33:16 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:34:16:34:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:34:16:34:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:34:16:34:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:34:16:34:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:34:16:34:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:34:16:34:16 | Load | test.cpp:35:16:35:16 | Load | +| test.cpp:34:16:34:16 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:35:16:35:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:35:16:35:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load | +| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... | +| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:41:15:41:28 | Store | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:41:15:41:28 | Store | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:42:15:42:15 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:43:16:43:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:41:15:41:28 | Store | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:41:15:41:28 | Store | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:44:16:44:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:45:16:45:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:46:16:46:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:47:16:47:16 | Load | +| test.cpp:41:15:41:28 | Store | test.cpp:48:16:48:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:42:15:42:15 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:42:15:42:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:43:16:43:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:42:15:42:15 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:42:15:42:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:42:15:42:15 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:43:16:43:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:43:16:43:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:43:16:43:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:43:16:43:16 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:44:16:44:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:43:16:43:16 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:44:16:44:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:44:16:44:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:44:16:44:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:44:16:44:16 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:45:16:45:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:45:16:45:16 | Load | test.cpp:46:16:46:16 | Load | +| test.cpp:45:16:45:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:45:16:45:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:45:16:45:16 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:46:16:46:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:46:16:46:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:46:16:46:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:46:16:46:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:46:16:46:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:46:16:46:16 | Load | test.cpp:47:16:47:16 | Load | +| test.cpp:46:16:46:16 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:47:16:47:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:47:16:47:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load | +| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load | +| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load | +| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:70:38:70:38 | Load | +| test.cpp:51:33:51:35 | Load indirection | test.cpp:60:34:60:37 | mk_array output argument | +| test.cpp:52:19:52:24 | call to malloc | test.cpp:51:7:51:14 | VariableAddress indirection | +| test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load | +| test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection | +| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store | +| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store | +| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... | +| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... | +| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection | +| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load | +| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load | +| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load | +| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] | +| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] | +| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:99:20:99:22 | arr indirection [begin] | +| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:119:18:119:25 | call to mk_array [begin] | +| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:91:36:91:38 | arr indirection [end] | +| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:95:36:95:38 | arr indirection [end] | +| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:99:35:99:37 | arr indirection [end] | +| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:119:18:119:25 | call to mk_array [end] | +| test.cpp:82:5:82:28 | Store | test.cpp:82:9:82:13 | arr indirection [post update] [begin] | +| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:80:9:80:16 | VariableAddress indirection [begin] | +| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:83:15:83:17 | arr indirection [begin] | +| test.cpp:82:17:82:22 | call to malloc | test.cpp:82:5:82:28 | Store | +| test.cpp:83:5:83:30 | Store | test.cpp:83:9:83:11 | arr indirection [post update] [end] | +| test.cpp:83:9:83:11 | arr indirection [post update] [end] | test.cpp:80:9:80:16 | VariableAddress indirection [end] | +| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin | +| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store | +| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store | +| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store | +| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... | +| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... | +| test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load | +| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin | +| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:47:91:47 | Load | +| test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load | +| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end | +| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load | +| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin | +| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load | +| test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load | +| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end | +| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load | +| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin | +| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load | +| test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load | +| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end | +| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load | +| test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] | +| test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] | +| test.cpp:104:27:104:29 | arr [begin] | test.cpp:113:20:113:22 | arr indirection [begin] | +| test.cpp:104:27:104:29 | arr [end] | test.cpp:105:36:105:38 | arr indirection [end] | +| test.cpp:104:27:104:29 | arr [end] | test.cpp:109:36:109:38 | arr indirection [end] | +| test.cpp:104:27:104:29 | arr [end] | test.cpp:113:35:113:37 | arr indirection [end] | +| test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin | +| test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:47:105:47 | Load | +| test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load | +| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end | +| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load | +| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin | +| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load | +| test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load | +| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end | +| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load | +| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin | +| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load | +| test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load | +| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end | +| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load | +| test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] | +| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] | +| test.cpp:124:15:124:20 | call to malloc | test.cpp:125:5:125:17 | Store | +| test.cpp:124:15:124:20 | call to malloc | test.cpp:126:15:126:15 | Load | +| test.cpp:125:5:125:17 | Store | test.cpp:125:9:125:13 | arr indirection [post update] [begin] | +| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:129:11:129:13 | arr indirection [begin] | +| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:133:11:133:13 | arr indirection [begin] | +| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:137:11:137:13 | arr indirection [begin] | +| test.cpp:129:11:129:13 | arr indirection [begin] | test.cpp:129:15:129:19 | begin | +| test.cpp:129:15:129:19 | begin | test.cpp:129:15:129:19 | Load | +| test.cpp:133:11:133:13 | arr indirection [begin] | test.cpp:133:15:133:19 | begin | +| test.cpp:133:15:133:19 | begin | test.cpp:133:15:133:19 | Load | +| test.cpp:137:11:137:13 | arr indirection [begin] | test.cpp:137:15:137:19 | begin | +| test.cpp:137:15:137:19 | begin | test.cpp:137:15:137:19 | Load | +| test.cpp:141:10:141:19 | VariableAddress indirection [begin] | test.cpp:150:20:150:29 | Call indirection [begin] | +| test.cpp:141:10:141:19 | VariableAddress indirection [begin] | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | +| test.cpp:141:10:141:19 | VariableAddress indirection [end] | test.cpp:150:20:150:29 | Call indirection [end] | +| test.cpp:141:10:141:19 | VariableAddress indirection [end] | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | +| test.cpp:143:5:143:29 | Store | test.cpp:143:10:143:14 | Load indirection [post update] [begin] | +| test.cpp:143:10:143:14 | Load indirection [post update] [begin] | test.cpp:141:10:141:19 | VariableAddress indirection [begin] | +| test.cpp:143:10:143:14 | Load indirection [post update] [begin] | test.cpp:144:16:144:18 | Load indirection [begin] | +| test.cpp:143:18:143:23 | call to malloc | test.cpp:143:5:143:29 | Store | +| test.cpp:144:5:144:32 | Store | test.cpp:144:10:144:12 | Load indirection [post update] [end] | +| test.cpp:144:10:144:12 | Load indirection [post update] [end] | test.cpp:141:10:141:19 | VariableAddress indirection [end] | +| test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin | +| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store | +| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store | +| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store | +| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... | +| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... | +| test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load | +| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] | +| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:156:20:156:22 | Load indirection [begin] | +| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:160:20:160:22 | Load indirection [begin] | +| test.cpp:150:20:150:29 | Call indirection [end] | test.cpp:156:37:156:39 | Load indirection [end] | +| test.cpp:152:20:152:22 | Load indirection [begin] | test.cpp:152:25:152:29 | begin | +| test.cpp:152:20:152:22 | Load indirection [begin] | test.cpp:152:49:152:49 | Load | +| test.cpp:152:25:152:29 | begin | test.cpp:152:49:152:49 | Load | +| test.cpp:156:20:156:22 | Load indirection [begin] | test.cpp:156:25:156:29 | begin | +| test.cpp:156:20:156:22 | Load indirection [begin] | test.cpp:156:49:156:49 | Load | +| test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load | +| test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end | +| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... | +| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... | +| test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load | +| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin | +| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load | +| test.cpp:160:25:160:29 | begin | test.cpp:160:48:160:48 | Load | +| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:166:20:166:22 | Load indirection [begin] | +| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:170:20:170:22 | Load indirection [begin] | +| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:174:20:174:22 | Load indirection [begin] | +| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:166:37:166:39 | Load indirection [end] | +| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:170:37:170:39 | Load indirection [end] | +| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:174:36:174:38 | Load indirection [end] | +| test.cpp:166:20:166:22 | Load indirection [begin] | test.cpp:166:25:166:29 | begin | +| test.cpp:166:20:166:22 | Load indirection [begin] | test.cpp:166:49:166:49 | Load | +| test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load | +| test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end | +| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load | +| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin | +| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load | +| test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load | +| test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end | +| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load | +| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin | +| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load | +| test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load | +| test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end | +| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load | +| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] | +| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] | +| test.cpp:188:15:188:20 | call to malloc | test.cpp:189:15:189:15 | Load | +#select +| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | +| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | +| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | +| test.cpp:20:14:20:21 | Load: * ... | test.cpp:16:15:16:20 | call to malloc | test.cpp:20:14:20:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:16:15:16:20 | call to malloc | call to malloc | test.cpp:17:19:17:22 | size | size | +| test.cpp:30:14:30:15 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:30:14:30:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... | +| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... | +| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... | +| test.cpp:42:14:42:15 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... | +| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... | +| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... | +| test.cpp:67:9:67:14 | Store: ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size | +| test.cpp:96:9:96:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size | +| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size | +| test.cpp:157:9:157:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:157:9:157:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size | +| test.cpp:171:9:171:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:171:9:171:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref new file mode 100644 index 00000000000..76da29dc7a0 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp new file mode 100644 index 00000000000..809c348c0b0 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -0,0 +1,191 @@ +char *malloc(int size); + +void test1(int size) { + char* p = malloc(size); + char* q = p + size; + char a = *q; // BAD + char b = *(q - 1); // GOOD + char c = *(q + 1); // BAD + char d = *(q + size); // BAD [NOT DETECTED] + char e = *(q - size); // GOOD + char f = *(q + size + 1); // BAD [NOT DETECTED] + char g = *(q - size - 1); // GOOD +} + +void test2(int size) { + char* p = malloc(size); + char* q = p + size - 1; + char a = *q; // GOOD + char b = *(q - 1); // GOOD + char c = *(q + 1); // BAD + char d = *(q + size); // BAD [NOT DETECTED] + char e = *(q - size); // GOOD + char f = *(q + size + 1); // BAD [NOT DETECTED] + char g = *(q - size - 1); // GOOD +} + +void test3(int size) { + char* p = malloc(size + 1); + char* q = p + (size + 1); + char a = *q; // BAD + char b = *(q - 1); // GOOD + char c = *(q + 1); // BAD + char d = *(q + size); // BAD [NOT DETECTED] + char e = *(q - size); // GOOD + char f = *(q + size + 1); // BAD [NOT DETECTED] + char g = *(q - size - 1); // GOOD +} + +void test4(int size) { + char* p = malloc(size - 1); + char* q = p + (size - 1); + char a = *q; // BAD + char b = *(q - 1); // GOOD + char c = *(q + 1); // BAD + char d = *(q + size); // BAD [NOT DETECTED] + char e = *(q - size); // GOOD + char f = *(q + size + 1); // BAD [NOT DETECTED] + char g = *(q - size - 1); // GOOD +} + +char* mk_array(int size, char** end) { + char* begin = malloc(size); + *end = begin + size; + + return begin; +} + +void test5(int size) { + char* end; + char* begin = mk_array(size, &end); + + for (char* p = begin; p != end; ++p) { + *p = 0; // GOOD + } + + for (char* p = begin; p <= end; ++p) { + *p = 0; // BAD + } + + for (char* p = begin; p < end; ++p) { + *p = 0; // GOOD + } +} + +struct array_t { + char* begin; + char* end; +}; + +array_t mk_array(int size) { + array_t arr; + arr.begin = malloc(size); + arr.end = arr.begin + size; + + return arr; +} + +void test6(int size) { + array_t arr = mk_array(size); + + for (char* p = arr.begin; p != arr.end; ++p) { + *p = 0; // GOOD + } + + for (char* p = arr.begin; p <= arr.end; ++p) { + *p = 0; // BAD + } + + for (char* p = arr.begin; p < arr.end; ++p) { + *p = 0; // GOOD + } +} + +void test7_callee(array_t arr) { + for (char* p = arr.begin; p != arr.end; ++p) { + *p = 0; // GOOD + } + + for (char* p = arr.begin; p <= arr.end; ++p) { + *p = 0; // BAD + } + + for (char* p = arr.begin; p < arr.end; ++p) { + *p = 0; // GOOD + } +} + +void test7(int size) { + test7_callee(mk_array(size)); +} + +void test8(int size) { + array_t arr; + char* p = malloc(size); + arr.begin = p; + arr.end = p + size; + + for (int i = 0; i < arr.end - arr.begin; i++) { + *(arr.begin + i) = 0; // GOOD + } + + for (int i = 0; i != arr.end - arr.begin; i++) { + *(arr.begin + i) = 0; // GOOD + } + + for (int i = 0; i <= arr.end - arr.begin; i++) { + *(arr.begin + i) = 0; // BAD [NOT DETECTED] + } +} + +array_t *mk_array_p(int size) { + array_t *arr = (array_t*) malloc(sizeof(array_t)); + arr->begin = malloc(size); + arr->end = arr->begin + size; + + return arr; +} + +void test9(int size) { + array_t *arr = mk_array_p(size); + + for (char* p = arr->begin; p != arr->end; ++p) { + *p = 0; // GOOD + } + + for (char* p = arr->begin; p <= arr->end; ++p) { + *p = 0; // BAD + } + + for (char* p = arr->begin; p < arr->end; ++p) { + *p = 0; // GOOD + } +} + +void test10_callee(array_t *arr) { + for (char* p = arr->begin; p != arr->end; ++p) { + *p = 0; // GOOD + } + + for (char* p = arr->begin; p <= arr->end; ++p) { + *p = 0; // BAD + } + + for (char* p = arr->begin; p < arr->end; ++p) { + *p = 0; // GOOD + } +} + +void test10(int size) { + test10_callee(mk_array_p(size)); +} + +void deref_plus_one(char* q) { + char a = *(q + 1); // BAD [NOT DETECTED] +} + +void test11(unsigned size) { + char *p = malloc(size); + char *q = p + size - 1; + deref_plus_one(q); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/builtins/type_traits/clang.cpp b/cpp/ql/test/library-tests/builtins/type_traits/clang.cpp new file mode 100644 index 00000000000..8cb32567820 --- /dev/null +++ b/cpp/ql/test/library-tests/builtins/type_traits/clang.cpp @@ -0,0 +1,88 @@ +// semmle-extractor-options: --clang --clang_version 100000 + +struct S { + void f() {} + int o; +}; + +using f_type = decltype(&S::f); +using o_type = decltype(&S::o); + +struct T; + +bool b_is_same1 = __is_same(int, int); +bool b_is_same2 = __is_same(int, float); + +bool b_is_function1 = __is_function(void(int)); +bool b_is_function2 = __is_function(int); + +bool b_is_array1 = __is_array(int[]); +bool b_is_array2 = __is_array(int); + +unsigned long b_array_rank1 = __array_rank(int[42][42]); +unsigned long b_array_rank2 = __array_rank(int); + +unsigned long b_array_extent1 = __array_extent(int[42][42], 1); +unsigned long b_array_extent2 = __array_extent(int[42][42], 2); +unsigned long b_array_extent3 = __array_extent(int, 0); + +bool bok_is_arithmetic1 = __is_arithmetic(S); +bool bok_is_arithmetic2 = __is_arithmetic(int); + +bool bok_is_complete_type1 = __is_complete_type(S); +bool bok_is_complete_type2 = __is_complete_type(T); + +bool bok_is_compound1 = __is_compound(S); +bool bok_is_compound2 = __is_compound(int); + +bool bok_is_const1 = __is_const(const int); +bool bok_is_const2 = __is_const(int); + +bool bok_is_floating_point1 = __is_floating_point(int); +bool bok_is_floating_point2 = __is_floating_point(float); + +bool bok_is_fundamental1 = __is_fundamental(S); +bool bok_is_fundamental2 = __is_fundamental(int); + +bool bok_is_integral1 = __is_integral(float); +bool bok_is_integral2 = __is_integral(int); + +bool bok_is_lvalue_reference1 = __is_lvalue_reference(int&); +bool bok_is_lvalue_reference2 = __is_lvalue_reference(int); + +bool bok_is_member_function_pointer1 = __is_member_function_pointer(f_type); +bool bok_is_member_function_pointer2 = __is_member_function_pointer(o_type); + +bool bok_is_member_object_pointer1 = __is_member_object_pointer(f_type); +bool bok_is_member_object_pointer2 = __is_member_object_pointer(o_type); + +bool bok_is_member_pointer1 = __is_member_pointer(f_type); +bool bok_is_member_pointer2 = __is_member_pointer(o_type); +bool bok_is_member_pointer3 = __is_member_pointer(int); + +bool bok_is_object1 = __is_object(int); +bool bok_is_object2 = __is_object(int&); + +bool bok_is_pointer1 = __is_pointer(int); +bool bok_is_pointer2 = __is_pointer(int*); + +bool bok_is_reference1 = __is_reference(int); +bool bok_is_reference2 = __is_reference(int&); + +bool bok_is_rvalue_reference1 = __is_rvalue_reference(int&&); +bool bok_is_rvalue_reference2 = __is_rvalue_reference(int); + +bool bok_is_scalar1 = __is_scalar(int); +bool bok_is_scalar2 = __is_scalar(int[]); + +bool bok_is_signed1 = __is_signed(int); +bool bok_is_signed2 = __is_signed(unsigned int); + +bool bok_is_unsigned1 = __is_unsigned(int); +bool bok_is_unsigned2 = __is_unsigned(unsigned int); + +bool bok_is_void1 = __is_void(void); +bool bok_is_void2 = __is_void(int); + +bool bok_is_volatile1 = __is_volatile(volatile int); +bool bok_is_volatile2 = __is_volatile(int); diff --git a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected index a19d917aaac..010d68711c6 100644 --- a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected +++ b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected @@ -1,3 +1,126 @@ +| clang.cpp:8:25:8:29 | f | | | +| clang.cpp:9:25:9:29 | o | | | +| clang.cpp:13:19:13:37 | __is_same | int,int | 1 | +| clang.cpp:13:19:13:37 | int | | | +| clang.cpp:13:19:13:37 | int | | | +| clang.cpp:14:19:14:39 | __is_same | int,float | 0 | +| clang.cpp:14:19:14:39 | float | | | +| clang.cpp:14:19:14:39 | int | | | +| clang.cpp:16:23:16:46 | ..()(..) | | | +| clang.cpp:16:23:16:46 | __is_function | ..()(..) | 1 | +| clang.cpp:17:23:17:40 | __is_function | int | 0 | +| clang.cpp:17:23:17:40 | int | | | +| clang.cpp:19:20:19:36 | __is_array | int[] | 1 | +| clang.cpp:19:20:19:36 | int[] | | | +| clang.cpp:20:20:20:34 | __is_array | int | 0 | +| clang.cpp:20:20:20:34 | int | | | +| clang.cpp:22:31:22:55 | __array_rank | int[42][42] | 2 | +| clang.cpp:22:31:22:55 | int[42][42] | | | +| clang.cpp:22:48:22:49 | 42 | | 42 | +| clang.cpp:22:48:22:49 | (unsigned long)... | | 42 | +| clang.cpp:22:52:22:53 | 42 | | 42 | +| clang.cpp:22:52:22:53 | (unsigned long)... | | 42 | +| clang.cpp:23:31:23:47 | __array_rank | int | 0 | +| clang.cpp:23:31:23:47 | int | | | +| clang.cpp:25:33:25:62 | __array_extent | int[42][42],1 | 42 | +| clang.cpp:25:33:25:62 | int[42][42] | | | +| clang.cpp:25:52:25:53 | 42 | | 42 | +| clang.cpp:25:52:25:53 | (unsigned long)... | | 42 | +| clang.cpp:25:56:25:57 | 42 | | 42 | +| clang.cpp:25:56:25:57 | (unsigned long)... | | 42 | +| clang.cpp:25:61:25:61 | 1 | | 1 | +| clang.cpp:26:33:26:62 | __array_extent | int[42][42],2 | 0 | +| clang.cpp:26:33:26:62 | int[42][42] | | | +| clang.cpp:26:52:26:53 | 42 | | 42 | +| clang.cpp:26:52:26:53 | (unsigned long)... | | 42 | +| clang.cpp:26:56:26:57 | 42 | | 42 | +| clang.cpp:26:56:26:57 | (unsigned long)... | | 42 | +| clang.cpp:26:61:26:61 | 2 | | 2 | +| clang.cpp:27:33:27:54 | __array_extent | int,0 | 0 | +| clang.cpp:27:33:27:54 | int | | | +| clang.cpp:27:53:27:53 | 0 | | 0 | +| clang.cpp:29:27:29:44 | S | | | +| clang.cpp:29:27:29:44 | __is_arithmetic | S | 0 | +| clang.cpp:30:27:30:46 | __is_arithmetic | int | 1 | +| clang.cpp:30:27:30:46 | int | | | +| clang.cpp:32:30:32:50 | S | | | +| clang.cpp:32:30:32:50 | __is_complete_type | S | 1 | +| clang.cpp:33:30:33:50 | T | | | +| clang.cpp:33:30:33:50 | __is_complete_type | T | 0 | +| clang.cpp:35:25:35:40 | S | | | +| clang.cpp:35:25:35:40 | __is_compound | S | 1 | +| clang.cpp:36:25:36:42 | __is_compound | int | 0 | +| clang.cpp:36:25:36:42 | int | | | +| clang.cpp:38:22:38:42 | __is_const | const int | 1 | +| clang.cpp:38:22:38:42 | const int | | | +| clang.cpp:39:22:39:36 | __is_const | int | 0 | +| clang.cpp:39:22:39:36 | int | | | +| clang.cpp:41:31:41:54 | __is_floating_point | int | 0 | +| clang.cpp:41:31:41:54 | int | | | +| clang.cpp:42:31:42:56 | __is_floating_point | float | 1 | +| clang.cpp:42:31:42:56 | float | | | +| clang.cpp:44:28:44:46 | S | | | +| clang.cpp:44:28:44:46 | __is_fundamental | S | 0 | +| clang.cpp:45:28:45:48 | __is_fundamental | int | 1 | +| clang.cpp:45:28:45:48 | int | | | +| clang.cpp:47:25:47:44 | __is_integral | float | 0 | +| clang.cpp:47:25:47:44 | float | | | +| clang.cpp:48:25:48:42 | __is_integral | int | 1 | +| clang.cpp:48:25:48:42 | int | | | +| clang.cpp:50:33:50:59 | __is_lvalue_reference | int & | 1 | +| clang.cpp:50:33:50:59 | int & | | | +| clang.cpp:51:33:51:58 | __is_lvalue_reference | int | 0 | +| clang.cpp:51:33:51:58 | int | | | +| clang.cpp:53:40:53:75 | __is_member_function_pointer | f_type | 1 | +| clang.cpp:53:40:53:75 | f_type | | | +| clang.cpp:54:40:54:75 | __is_member_function_pointer | o_type | 0 | +| clang.cpp:54:40:54:75 | o_type | | | +| clang.cpp:56:38:56:71 | __is_member_object_pointer | f_type | 0 | +| clang.cpp:56:38:56:71 | f_type | | | +| clang.cpp:57:38:57:71 | __is_member_object_pointer | o_type | 1 | +| clang.cpp:57:38:57:71 | o_type | | | +| clang.cpp:59:31:59:57 | __is_member_pointer | f_type | 1 | +| clang.cpp:59:31:59:57 | f_type | | | +| clang.cpp:60:31:60:57 | __is_member_pointer | o_type | 1 | +| clang.cpp:60:31:60:57 | o_type | | | +| clang.cpp:61:31:61:54 | __is_member_pointer | int | 0 | +| clang.cpp:61:31:61:54 | int | | | +| clang.cpp:63:23:63:38 | __is_object | int | 1 | +| clang.cpp:63:23:63:38 | int | | | +| clang.cpp:64:23:64:39 | __is_object | int & | 0 | +| clang.cpp:64:23:64:39 | int & | | | +| clang.cpp:66:24:66:40 | __is_pointer | int | 0 | +| clang.cpp:66:24:66:40 | int | | | +| clang.cpp:67:24:67:41 | __is_pointer | int * | 1 | +| clang.cpp:67:24:67:41 | int * | | | +| clang.cpp:69:26:69:44 | __is_reference | int | 0 | +| clang.cpp:69:26:69:44 | int | | | +| clang.cpp:70:26:70:45 | __is_reference | int & | 1 | +| clang.cpp:70:26:70:45 | int & | | | +| clang.cpp:72:33:72:60 | __is_rvalue_reference | int && | 1 | +| clang.cpp:72:33:72:60 | int && | | | +| clang.cpp:73:33:73:58 | __is_rvalue_reference | int | 0 | +| clang.cpp:73:33:73:58 | int | | | +| clang.cpp:75:23:75:38 | __is_scalar | int | 1 | +| clang.cpp:75:23:75:38 | int | | | +| clang.cpp:76:23:76:40 | __is_scalar | int[] | 0 | +| clang.cpp:76:23:76:40 | int[] | | | +| clang.cpp:78:23:78:38 | __is_signed | int | 1 | +| clang.cpp:78:23:78:38 | int | | | +| clang.cpp:79:23:79:47 | __is_signed | unsigned int | 0 | +| clang.cpp:79:23:79:47 | unsigned int | | | +| clang.cpp:81:25:81:42 | __is_unsigned | int | 0 | +| clang.cpp:81:25:81:42 | int | | | +| clang.cpp:82:25:82:51 | __is_unsigned | unsigned int | 1 | +| clang.cpp:82:25:82:51 | unsigned int | | | +| clang.cpp:84:21:84:35 | __is_void | void | 1 | +| clang.cpp:84:21:84:35 | void | | | +| clang.cpp:85:21:85:34 | __is_void | int | 0 | +| clang.cpp:85:21:85:34 | int | | | +| clang.cpp:87:25:87:51 | __is_volatile | volatile int | 1 | +| clang.cpp:87:25:87:51 | volatile int | | | +| clang.cpp:88:25:88:42 | __is_volatile | int | 0 | +| clang.cpp:88:25:88:42 | int | | | | file://:0:0:0:0 | 0 | | 0 | | file://:0:0:0:0 | 1 | | 1 | | file://:0:0:0:0 | 2 | | 2 | @@ -313,3 +436,15 @@ | ms.cpp:265:49:265:88 | int | | | | ms.cpp:266:49:266:90 | __has_unique_object_representations | float | 0 | | ms.cpp:266:49:266:90 | float | | | +| ms.cpp:268:36:268:68 | __is_layout_compatible | int,long | 0 | +| ms.cpp:268:36:268:68 | int | | | +| ms.cpp:268:36:268:68 | long | | | +| ms.cpp:269:36:269:75 | __is_layout_compatible | int *,int *const | 1 | +| ms.cpp:269:36:269:75 | int * | | | +| ms.cpp:269:36:269:75 | int *const | | | +| ms.cpp:271:51:271:101 | __is_pointer_interconvertible_base_of | empty,empty | 1 | +| ms.cpp:271:51:271:101 | empty | | | +| ms.cpp:271:51:271:101 | empty | | | +| ms.cpp:272:51:272:104 | __is_pointer_interconvertible_base_of | empty,abstract | 0 | +| ms.cpp:272:51:272:104 | abstract | | | +| ms.cpp:272:51:272:104 | empty | | | diff --git a/cpp/ql/test/library-tests/builtins/type_traits/ms.cpp b/cpp/ql/test/library-tests/builtins/type_traits/ms.cpp index 91d6245cc35..6083f9dc6bb 100644 --- a/cpp/ql/test/library-tests/builtins/type_traits/ms.cpp +++ b/cpp/ql/test/library-tests/builtins/type_traits/ms.cpp @@ -1,4 +1,4 @@ - +// semmle-extractor-options: --microsoft --microsoft_version 1600 class empty { }; @@ -264,4 +264,10 @@ void f(void) { bool b_has_unique_object_representations1 = __has_unique_object_representations(int); bool b_has_unique_object_representations2 = __has_unique_object_representations(float); + + bool b_is_layout_compatible1 = __is_layout_compatible(int, long); + bool b_is_layout_compatible2 = __is_layout_compatible(int*, int* const); + + bool b_is_pointer_interconvertible_base_of1 = __is_pointer_interconvertible_base_of(empty, empty); + bool b_is_pointer_interconvertible_base_of2 = __is_pointer_interconvertible_base_of(empty, abstract); } diff --git a/cpp/ql/test/library-tests/builtins/type_traits/options b/cpp/ql/test/library-tests/builtins/type_traits/options deleted file mode 100644 index dd5426f016a..00000000000 --- a/cpp/ql/test/library-tests/builtins/type_traits/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --microsoft --microsoft_version 1600 diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 1523c0eef25..4153f37c024 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -14161,6 +14161,221 @@ ir.cpp: # 1851| Type = [PointerType] const char * # 1851| ValueCategory = prvalue # 1852| getStmt(2): [ReturnStmt] return ... +# 1855| [CopyAssignmentOperator] missing_declaration_entries::S& missing_declaration_entries::S::operator=(missing_declaration_entries::S const&) +# 1855| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const S & +# 1855| [MoveAssignmentOperator] missing_declaration_entries::S& missing_declaration_entries::S::operator=(missing_declaration_entries::S&&) +# 1855| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] S && +# 1859| [CopyAssignmentOperator] missing_declaration_entries::Bar1& missing_declaration_entries::Bar1::operator=(missing_declaration_entries::Bar1 const&) +# 1859| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const Bar1 & +# 1859| [MoveAssignmentOperator] missing_declaration_entries::Bar1& missing_declaration_entries::Bar1::operator=(missing_declaration_entries::Bar1&&) +# 1859| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] Bar1 && +# 1862| [MemberFunction] void* missing_declaration_entries::Bar1::missing_type_decl_entry(missing_declaration_entries::Bar1::pointer) +# 1862| : +# 1862| getParameter(0): [Parameter] p +# 1862| Type = [CTypedefType,NestedTypedefType] pointer +# 1862| getEntryPoint(): [BlockStmt] { ... } +# 1863| getStmt(0): [DeclStmt] declaration +# 1863| getDeclarationEntry(0): [TypeDeclarationEntry] declaration of _Res +# 1863| Type = [CTypedefType,LocalTypedefType] _Res +# 1864| getStmt(1): [ReturnStmt] return ... +# 1864| getExpr(): [VariableAccess] p +# 1864| Type = [CTypedefType,NestedTypedefType] pointer +# 1864| ValueCategory = prvalue(load) +# 1864| getExpr().getFullyConverted(): [CStyleCast] (void *)... +# 1864| Conversion = [PointerConversion] pointer conversion +# 1864| Type = [VoidPointerType] void * +# 1864| ValueCategory = prvalue +# 1862| [MemberFunction] void* missing_declaration_entries::Bar1::missing_type_decl_entry(missing_declaration_entries::Bar1::pointer) +# 1862| : +# 1862| getParameter(0): [Parameter] p +# 1862| Type = [CTypedefType,NestedTypedefType] pointer +# 1862| getEntryPoint(): [BlockStmt] { ... } +# 1863| getStmt(0): [DeclStmt] declaration +# 1864| getStmt(1): [ReturnStmt] return ... +# 1864| getExpr(): [VariableAccess] p +# 1864| Type = [CTypedefType,NestedTypedefType] pointer +# 1864| ValueCategory = prvalue(load) +# 1864| getExpr().getFullyConverted(): [CStyleCast] (void *)... +# 1864| Conversion = [PointerConversion] pointer conversion +# 1864| Type = [VoidPointerType] void * +# 1864| ValueCategory = prvalue +# 1868| [TopLevelFunction] void missing_declaration_entries::test1() +# 1868| : +# 1868| getEntryPoint(): [BlockStmt] { ... } +# 1869| getStmt(0): [DeclStmt] declaration +# 1869| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b +# 1869| Type = [ClassTemplateInstantiation,Struct] Bar1 +# 1870| getStmt(1): [ExprStmt] ExprStmt +# 1870| getExpr(): [FunctionCall] call to missing_type_decl_entry +# 1870| Type = [VoidPointerType] void * +# 1870| ValueCategory = prvalue +# 1870| getQualifier(): [VariableAccess] b +# 1870| Type = [ClassTemplateInstantiation,Struct] Bar1 +# 1870| ValueCategory = lvalue +# 1870| getArgument(0): [Literal] 0 +# 1870| Type = [NullPointerType] decltype(nullptr) +# 1870| Value = [Literal] 0 +# 1870| ValueCategory = prvalue +# 1870| getArgument(0).getFullyConverted(): [CStyleCast] (pointer)... +# 1870| Conversion = [PointerConversion] pointer conversion +# 1870| Type = [CTypedefType,NestedTypedefType] pointer +# 1870| Value = [CStyleCast] 0 +# 1870| ValueCategory = prvalue +# 1871| getStmt(2): [ReturnStmt] return ... +# 1873| [CopyAssignmentOperator] missing_declaration_entries::Bar2& missing_declaration_entries::Bar2::operator=(missing_declaration_entries::Bar2 const&) +# 1873| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const Bar2 & +# 1873| [MoveAssignmentOperator] missing_declaration_entries::Bar2& missing_declaration_entries::Bar2::operator=(missing_declaration_entries::Bar2&&) +# 1873| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] Bar2 && +# 1875| [MemberFunction] int missing_declaration_entries::Bar2::two_missing_variable_declaration_entries() +# 1875| : +# 1875| getEntryPoint(): [BlockStmt] { ... } +# 1876| getStmt(0): [DeclStmt] declaration +# 1876| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 1876| Type = [ArrayType] int[10] +# 1876| getDeclarationEntry(1): [VariableDeclarationEntry] definition of y +# 1876| Type = [ArrayType] int[10] +# 1877| getStmt(1): [ExprStmt] ExprStmt +# 1877| getExpr(): [AssignExpr] ... = ... +# 1877| Type = [IntType] int +# 1877| ValueCategory = lvalue +# 1877| getLValue(): [PointerDereferenceExpr] * ... +# 1877| Type = [IntType] int +# 1877| ValueCategory = lvalue +# 1877| getOperand(): [VariableAccess] x +# 1877| Type = [ArrayType] int[10] +# 1877| ValueCategory = lvalue +# 1877| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1877| Type = [IntPointerType] int * +# 1877| ValueCategory = prvalue +# 1877| getRValue(): [Literal] 10 +# 1877| Type = [IntType] int +# 1877| Value = [Literal] 10 +# 1877| ValueCategory = prvalue +# 1878| getStmt(2): [ExprStmt] ExprStmt +# 1878| getExpr(): [AssignExpr] ... = ... +# 1878| Type = [IntType] int +# 1878| ValueCategory = lvalue +# 1878| getLValue(): [PointerDereferenceExpr] * ... +# 1878| Type = [IntType] int +# 1878| ValueCategory = lvalue +# 1878| getOperand(): [VariableAccess] y +# 1878| Type = [ArrayType] int[10] +# 1878| ValueCategory = lvalue +# 1878| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1878| Type = [IntPointerType] int * +# 1878| ValueCategory = prvalue +# 1878| getRValue(): [Literal] 10 +# 1878| Type = [IntType] int +# 1878| Value = [Literal] 10 +# 1878| ValueCategory = prvalue +# 1879| getStmt(3): [ReturnStmt] return ... +# 1879| getExpr(): [AddExpr] ... + ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue +# 1879| getLeftOperand(): [PointerDereferenceExpr] * ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue(load) +# 1879| getOperand(): [VariableAccess] x +# 1879| Type = [ArrayType] int[10] +# 1879| ValueCategory = lvalue +# 1879| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1879| Type = [IntPointerType] int * +# 1879| ValueCategory = prvalue +# 1879| getRightOperand(): [PointerDereferenceExpr] * ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue(load) +# 1879| getOperand(): [VariableAccess] y +# 1879| Type = [ArrayType] int[10] +# 1879| ValueCategory = lvalue +# 1879| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1879| Type = [IntPointerType] int * +# 1879| ValueCategory = prvalue +# 1875| [MemberFunction] int missing_declaration_entries::Bar2::two_missing_variable_declaration_entries() +# 1875| : +# 1875| getEntryPoint(): [BlockStmt] { ... } +# 1876| getStmt(0): [DeclStmt] declaration +# 1877| getStmt(1): [ExprStmt] ExprStmt +# 1877| getExpr(): [AssignExpr] ... = ... +# 1877| Type = [IntType] int +# 1877| ValueCategory = lvalue +# 1877| getLValue(): [PointerDereferenceExpr] * ... +# 1877| Type = [IntType] int +# 1877| ValueCategory = lvalue +# 1877| getOperand(): [VariableAccess] x +# 1877| Type = [ArrayType] int[10] +# 1877| ValueCategory = lvalue +# 1877| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1877| Type = [IntPointerType] int * +# 1877| ValueCategory = prvalue +# 1877| getRValue(): [Literal] 10 +# 1877| Type = [IntType] int +# 1877| Value = [Literal] 10 +# 1877| ValueCategory = prvalue +# 1878| getStmt(2): [ExprStmt] ExprStmt +# 1878| getExpr(): [AssignExpr] ... = ... +# 1878| Type = [IntType] int +# 1878| ValueCategory = lvalue +# 1878| getLValue(): [PointerDereferenceExpr] * ... +# 1878| Type = [IntType] int +# 1878| ValueCategory = lvalue +# 1878| getOperand(): [VariableAccess] y +# 1878| Type = [ArrayType] int[10] +# 1878| ValueCategory = lvalue +# 1878| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1878| Type = [IntPointerType] int * +# 1878| ValueCategory = prvalue +# 1878| getRValue(): [Literal] 10 +# 1878| Type = [IntType] int +# 1878| Value = [Literal] 10 +# 1878| ValueCategory = prvalue +# 1879| getStmt(3): [ReturnStmt] return ... +# 1879| getExpr(): [AddExpr] ... + ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue +# 1879| getLeftOperand(): [PointerDereferenceExpr] * ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue(load) +# 1879| getOperand(): [VariableAccess] x +# 1879| Type = [ArrayType] int[10] +# 1879| ValueCategory = lvalue +# 1879| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1879| Type = [IntPointerType] int * +# 1879| ValueCategory = prvalue +# 1879| getRightOperand(): [PointerDereferenceExpr] * ... +# 1879| Type = [IntType] int +# 1879| ValueCategory = prvalue(load) +# 1879| getOperand(): [VariableAccess] y +# 1879| Type = [ArrayType] int[10] +# 1879| ValueCategory = lvalue +# 1879| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 1879| Type = [IntPointerType] int * +# 1879| ValueCategory = prvalue +# 1883| [TopLevelFunction] void missing_declaration_entries::test2() +# 1883| : +# 1883| getEntryPoint(): [BlockStmt] { ... } +# 1884| getStmt(0): [DeclStmt] declaration +# 1884| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b +# 1884| Type = [ClassTemplateInstantiation,Struct] Bar2 +# 1885| getStmt(1): [ExprStmt] ExprStmt +# 1885| getExpr(): [FunctionCall] call to two_missing_variable_declaration_entries +# 1885| Type = [IntType] int +# 1885| ValueCategory = prvalue +# 1885| getQualifier(): [VariableAccess] b +# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2 +# 1885| ValueCategory = lvalue +# 1886| getStmt(2): [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| : diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 3e43f5b0d61..5a8d500fa43 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1851,4 +1851,39 @@ void magicvars() { const char *strfunc = __func__; } +namespace missing_declaration_entries { + struct S {}; + + template struct pair{}; + + template struct Bar1 { + typedef S* pointer; + + void* missing_type_decl_entry(pointer p) { + typedef pair _Res; + return p; + } + }; + + void test1() { + Bar1 b; + b.missing_type_decl_entry(nullptr); + } + + template struct Bar2 { + + int two_missing_variable_declaration_entries() { + int x[10], y[10]; + *x = 10; + *y = 10; + return *x + *y; + } + }; + + void test2() { + Bar2 b; + b.two_missing_variable_declaration_entries(); + } +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected index 61ca670b978..eb63841daba 100644 --- a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected +++ b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected @@ -5303,10 +5303,10 @@ | ir.cpp:1077:39:1077:39 | Address | &:r1077_7 | | ir.cpp:1077:39:1077:39 | Load | m1077_6 | | ir.cpp:1077:39:1077:39 | SideEffect | m1077_8 | -| ir.cpp:1078:5:1078:5 | Address | &:r1078_1 | -| ir.cpp:1078:5:1078:5 | Address | &:r1078_7 | -| ir.cpp:1078:5:1078:5 | Address | &:r1078_15 | -| ir.cpp:1078:14:1078:14 | Address | &:r1078_33 | +| ir.cpp:1078:5:1082:5 | Address | &:r1078_1 | +| ir.cpp:1078:5:1082:5 | Address | &:r1078_7 | +| ir.cpp:1078:5:1082:5 | Address | &:r1078_15 | +| ir.cpp:1078:5:1082:5 | Address | &:r1078_33 | | ir.cpp:1078:18:1078:18 | Address | &:r1078_2 | | ir.cpp:1078:18:1078:18 | Address | &:r1078_8 | | ir.cpp:1078:18:1078:18 | Address | &:r1078_16 | @@ -5369,10 +5369,10 @@ | ir.cpp:1079:13:1079:13 | Load | m1078_40 | | ir.cpp:1079:13:1079:17 | Condition | r1079_4 | | ir.cpp:1079:17:1079:17 | Right | r1079_3 | -| ir.cpp:1084:5:1084:5 | Address | &:r1084_1 | -| ir.cpp:1084:5:1084:5 | Address | &:r1084_7 | -| ir.cpp:1084:5:1084:5 | Address | &:r1084_15 | -| ir.cpp:1084:21:1084:21 | Address | &:r1084_42 | +| ir.cpp:1084:5:1088:5 | Address | &:r1084_1 | +| ir.cpp:1084:5:1088:5 | Address | &:r1084_7 | +| ir.cpp:1084:5:1088:5 | Address | &:r1084_15 | +| ir.cpp:1084:5:1088:5 | Address | &:r1084_42 | | ir.cpp:1084:25:1084:25 | Address | &:r1084_2 | | ir.cpp:1084:25:1084:25 | Address | &:r1084_8 | | ir.cpp:1084:25:1084:25 | Address | &:r1084_16 | @@ -8650,6 +8650,97 @@ | ir.cpp:1851:17:1851:23 | Address | &:r1851_1 | | ir.cpp:1851:27:1851:34 | StoreValue | r1851_3 | | ir.cpp:1851:27:1851:34 | Unary | r1851_2 | +| ir.cpp:1862:15:1862:15 | Address | &:r1862_5 | +| ir.cpp:1862:15:1862:15 | Address | &:r1862_5 | +| ir.cpp:1862:15:1862:15 | Address | &:r1862_7 | +| ir.cpp:1862:15:1862:15 | Address | &:r1862_7 | +| ir.cpp:1862:15:1862:15 | Address | &:r1862_15 | +| ir.cpp:1862:15:1862:15 | ChiPartial | partial:m1862_3 | +| ir.cpp:1862:15:1862:15 | ChiTotal | total:m1862_2 | +| ir.cpp:1862:15:1862:15 | Load | m1862_6 | +| ir.cpp:1862:15:1862:15 | Load | m1864_5 | +| ir.cpp:1862:15:1862:15 | SideEffect | m1862_3 | +| ir.cpp:1862:15:1862:15 | SideEffect | m1862_8 | +| ir.cpp:1862:47:1862:47 | Address | &:r1862_9 | +| ir.cpp:1862:47:1862:47 | Address | &:r1862_9 | +| ir.cpp:1862:47:1862:47 | Address | &:r1862_11 | +| ir.cpp:1862:47:1862:47 | Address | &:r1862_11 | +| ir.cpp:1862:47:1862:47 | Load | m1862_10 | +| ir.cpp:1862:47:1862:47 | SideEffect | m1862_12 | +| ir.cpp:1864:13:1864:21 | Address | &:r1864_1 | +| ir.cpp:1864:20:1864:20 | Address | &:r1864_2 | +| ir.cpp:1864:20:1864:20 | Load | m1862_10 | +| ir.cpp:1864:20:1864:20 | StoreValue | r1864_4 | +| ir.cpp:1864:20:1864:20 | Unary | r1864_3 | +| ir.cpp:1868:10:1868:14 | ChiPartial | partial:m1868_3 | +| ir.cpp:1868:10:1868:14 | ChiTotal | total:m1868_2 | +| ir.cpp:1868:10:1868:14 | SideEffect | ~m1870_12 | +| ir.cpp:1869:19:1869:19 | Address | &:r1869_1 | +| ir.cpp:1870:9:1870:9 | Address | &:r1870_1 | +| ir.cpp:1870:9:1870:9 | Address | &:r1870_1 | +| ir.cpp:1870:9:1870:9 | Arg(this) | this:r1870_1 | +| ir.cpp:1870:9:1870:9 | ChiPartial | partial:m1870_9 | +| ir.cpp:1870:9:1870:9 | ChiTotal | total:m1869_2 | +| ir.cpp:1870:9:1870:9 | SideEffect | m1869_2 | +| ir.cpp:1870:11:1870:33 | CallTarget | func:r1870_2 | +| ir.cpp:1870:11:1870:33 | ChiPartial | partial:m1870_5 | +| ir.cpp:1870:11:1870:33 | ChiTotal | total:m1868_4 | +| ir.cpp:1870:11:1870:33 | SideEffect | ~m1868_4 | +| ir.cpp:1870:35:1870:41 | Address | &:r1870_3 | +| ir.cpp:1870:35:1870:41 | Address | &:r1870_3 | +| ir.cpp:1870:35:1870:41 | Arg(0) | 0:r1870_3 | +| ir.cpp:1870:35:1870:41 | ChiPartial | partial:m1870_11 | +| ir.cpp:1870:35:1870:41 | ChiTotal | total:m1870_6 | +| ir.cpp:1870:35:1870:41 | SideEffect | ~m1870_6 | +| ir.cpp:1875:13:1875:13 | Address | &:r1875_5 | +| ir.cpp:1875:13:1875:13 | Address | &:r1875_5 | +| ir.cpp:1875:13:1875:13 | Address | &:r1875_7 | +| ir.cpp:1875:13:1875:13 | Address | &:r1875_7 | +| ir.cpp:1875:13:1875:13 | Address | &:r1875_10 | +| ir.cpp:1875:13:1875:13 | ChiPartial | partial:m1875_3 | +| ir.cpp:1875:13:1875:13 | ChiTotal | total:m1875_2 | +| ir.cpp:1875:13:1875:13 | Load | m1875_6 | +| ir.cpp:1875:13:1875:13 | Load | m1879_9 | +| ir.cpp:1875:13:1875:13 | SideEffect | m1875_3 | +| ir.cpp:1875:13:1875:13 | SideEffect | m1875_8 | +| ir.cpp:1876:13:1876:29 | Address | &:r1876_1 | +| ir.cpp:1876:13:1876:29 | Address | &:r1876_3 | +| ir.cpp:1877:13:1877:14 | Address | &:r1877_4 | +| ir.cpp:1877:13:1877:19 | ChiPartial | partial:m1877_5 | +| ir.cpp:1877:13:1877:19 | ChiTotal | total:m1876_2 | +| ir.cpp:1877:14:1877:14 | Unary | r1877_2 | +| ir.cpp:1877:14:1877:14 | Unary | r1877_3 | +| ir.cpp:1877:18:1877:19 | StoreValue | r1877_1 | +| ir.cpp:1878:13:1878:14 | Address | &:r1878_4 | +| ir.cpp:1878:13:1878:19 | ChiPartial | partial:m1878_5 | +| ir.cpp:1878:13:1878:19 | ChiTotal | total:m1876_4 | +| ir.cpp:1878:14:1878:14 | Unary | r1878_2 | +| ir.cpp:1878:14:1878:14 | Unary | r1878_3 | +| ir.cpp:1878:18:1878:19 | StoreValue | r1878_1 | +| ir.cpp:1879:13:1879:27 | Address | &:r1879_1 | +| ir.cpp:1879:20:1879:21 | Left | r1879_4 | +| ir.cpp:1879:20:1879:21 | Load | m1877_5 | +| ir.cpp:1879:20:1879:26 | StoreValue | r1879_8 | +| ir.cpp:1879:21:1879:21 | Address | &:r1879_3 | +| ir.cpp:1879:21:1879:21 | Unary | r1879_2 | +| ir.cpp:1879:25:1879:26 | Load | m1878_5 | +| ir.cpp:1879:25:1879:26 | Right | r1879_7 | +| ir.cpp:1879:26:1879:26 | Address | &:r1879_6 | +| ir.cpp:1879:26:1879:26 | Unary | r1879_5 | +| ir.cpp:1883:10:1883:14 | ChiPartial | partial:m1883_3 | +| ir.cpp:1883:10:1883:14 | ChiTotal | total:m1883_2 | +| ir.cpp:1883:10:1883:14 | SideEffect | ~m1885_5 | +| ir.cpp:1884:19:1884:19 | Address | &:r1884_1 | +| ir.cpp:1885:9:1885:9 | Address | &:r1885_1 | +| ir.cpp:1885:9:1885:9 | Address | &:r1885_1 | +| ir.cpp:1885:9:1885:9 | Arg(this) | this:r1885_1 | +| ir.cpp:1885:9:1885:9 | ChiPartial | partial:m1885_7 | +| ir.cpp:1885:9:1885:9 | ChiTotal | total:m1884_2 | +| ir.cpp:1885:9:1885:9 | SideEffect | m1884_2 | +| ir.cpp:1885:11:1885:50 | CallTarget | func:r1885_2 | +| ir.cpp:1885:11:1885:50 | ChiPartial | partial:m1885_4 | +| ir.cpp:1885:11:1885:50 | ChiTotal | total:m1883_4 | +| ir.cpp:1885:11:1885:50 | SideEffect | ~m1883_4 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_5 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_5 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_7 | diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index cc50472385b..600d74bc916 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr>::~unique_ptr() | void std::unique_ptr>::~unique_ptr() | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 1d059ce6a1e..cb8bd0465da 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -9932,6 +9932,108 @@ ir.cpp: # 1849| v1849_5(void) = AliasedUse : ~m? # 1849| v1849_6(void) = ExitFunction : +# 1862| void* missing_declaration_entries::Bar1::missing_type_decl_entry(missing_declaration_entries::Bar1::pointer) +# 1862| Block 0 +# 1862| v1862_1(void) = EnterFunction : +# 1862| mu1862_2(unknown) = AliasedDefinition : +# 1862| mu1862_3(unknown) = InitializeNonLocal : +# 1862| r1862_4(glval) = VariableAddress[#this] : +# 1862| mu1862_5(glval>) = InitializeParameter[#this] : &:r1862_4 +# 1862| r1862_6(glval>) = Load[#this] : &:r1862_4, ~m? +# 1862| mu1862_7(Bar1) = InitializeIndirection[#this] : &:r1862_6 +# 1862| r1862_8(glval) = VariableAddress[p] : +# 1862| mu1862_9(S *) = InitializeParameter[p] : &:r1862_8 +# 1862| r1862_10(S *) = Load[p] : &:r1862_8, ~m? +# 1862| mu1862_11(unknown) = InitializeIndirection[p] : &:r1862_10 +# 1864| r1864_1(glval) = VariableAddress[#return] : +# 1864| r1864_2(glval) = VariableAddress[p] : +# 1864| r1864_3(S *) = Load[p] : &:r1864_2, ~m? +# 1864| r1864_4(void *) = Convert : r1864_3 +# 1864| mu1864_5(void *) = Store[#return] : &:r1864_1, r1864_4 +# 1862| v1862_12(void) = ReturnIndirection[#this] : &:r1862_6, ~m? +# 1862| v1862_13(void) = ReturnIndirection[p] : &:r1862_10, ~m? +# 1862| r1862_14(glval) = VariableAddress[#return] : +# 1862| v1862_15(void) = ReturnValue : &:r1862_14, ~m? +# 1862| v1862_16(void) = AliasedUse : ~m? +# 1862| v1862_17(void) = ExitFunction : + +# 1868| void missing_declaration_entries::test1() +# 1868| Block 0 +# 1868| v1868_1(void) = EnterFunction : +# 1868| mu1868_2(unknown) = AliasedDefinition : +# 1868| mu1868_3(unknown) = InitializeNonLocal : +# 1869| r1869_1(glval>) = VariableAddress[b] : +# 1869| mu1869_2(Bar1) = Uninitialized[b] : &:r1869_1 +# 1870| r1870_1(glval>) = VariableAddress[b] : +# 1870| r1870_2(glval) = FunctionAddress[missing_type_decl_entry] : +# 1870| r1870_3(S *) = Constant[0] : +# 1870| r1870_4(void *) = Call[missing_type_decl_entry] : func:r1870_2, this:r1870_1, 0:r1870_3 +# 1870| mu1870_5(unknown) = ^CallSideEffect : ~m? +# 1870| v1870_6(void) = ^IndirectReadSideEffect[-1] : &:r1870_1, ~m? +# 1870| v1870_7(void) = ^BufferReadSideEffect[0] : &:r1870_3, ~m? +# 1870| mu1870_8(Bar1) = ^IndirectMayWriteSideEffect[-1] : &:r1870_1 +# 1870| mu1870_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1870_3 +# 1871| v1871_1(void) = NoOp : +# 1868| v1868_4(void) = ReturnVoid : +# 1868| v1868_5(void) = AliasedUse : ~m? +# 1868| v1868_6(void) = ExitFunction : + +# 1875| int missing_declaration_entries::Bar2::two_missing_variable_declaration_entries() +# 1875| Block 0 +# 1875| v1875_1(void) = EnterFunction : +# 1875| mu1875_2(unknown) = AliasedDefinition : +# 1875| mu1875_3(unknown) = InitializeNonLocal : +# 1875| r1875_4(glval) = VariableAddress[#this] : +# 1875| mu1875_5(glval>) = InitializeParameter[#this] : &:r1875_4 +# 1875| r1875_6(glval>) = Load[#this] : &:r1875_4, ~m? +# 1875| mu1875_7(Bar2) = InitializeIndirection[#this] : &:r1875_6 +# 1876| r1876_1(glval) = VariableAddress[x] : +# 1876| mu1876_2(int[10]) = Uninitialized[x] : &:r1876_1 +# 1876| r1876_3(glval) = VariableAddress[y] : +# 1876| mu1876_4(int[10]) = Uninitialized[y] : &:r1876_3 +# 1877| r1877_1(int) = Constant[10] : +# 1877| r1877_2(glval) = VariableAddress[x] : +# 1877| r1877_3(int *) = Convert : r1877_2 +# 1877| r1877_4(glval) = CopyValue : r1877_3 +# 1877| mu1877_5(int) = Store[?] : &:r1877_4, r1877_1 +# 1878| r1878_1(int) = Constant[10] : +# 1878| r1878_2(glval) = VariableAddress[y] : +# 1878| r1878_3(int *) = Convert : r1878_2 +# 1878| r1878_4(glval) = CopyValue : r1878_3 +# 1878| mu1878_5(int) = Store[?] : &:r1878_4, r1878_1 +# 1879| r1879_1(glval) = VariableAddress[#return] : +# 1879| r1879_2(glval) = VariableAddress[x] : +# 1879| r1879_3(int *) = Convert : r1879_2 +# 1879| r1879_4(int) = Load[?] : &:r1879_3, ~m? +# 1879| r1879_5(glval) = VariableAddress[y] : +# 1879| r1879_6(int *) = Convert : r1879_5 +# 1879| r1879_7(int) = Load[?] : &:r1879_6, ~m? +# 1879| r1879_8(int) = Add : r1879_4, r1879_7 +# 1879| mu1879_9(int) = Store[#return] : &:r1879_1, r1879_8 +# 1875| v1875_8(void) = ReturnIndirection[#this] : &:r1875_6, ~m? +# 1875| r1875_9(glval) = VariableAddress[#return] : +# 1875| v1875_10(void) = ReturnValue : &:r1875_9, ~m? +# 1875| v1875_11(void) = AliasedUse : ~m? +# 1875| v1875_12(void) = ExitFunction : + +# 1883| void missing_declaration_entries::test2() +# 1883| Block 0 +# 1883| v1883_1(void) = EnterFunction : +# 1883| mu1883_2(unknown) = AliasedDefinition : +# 1883| mu1883_3(unknown) = InitializeNonLocal : +# 1884| r1884_1(glval>) = VariableAddress[b] : +# 1884| mu1884_2(Bar2) = Uninitialized[b] : &:r1884_1 +# 1885| r1885_1(glval>) = VariableAddress[b] : +# 1885| r1885_2(glval) = FunctionAddress[two_missing_variable_declaration_entries] : +# 1885| r1885_3(int) = Call[two_missing_variable_declaration_entries] : func:r1885_2, this:r1885_1 +# 1885| mu1885_4(unknown) = ^CallSideEffect : ~m? +# 1885| v1885_5(void) = ^IndirectReadSideEffect[-1] : &:r1885_1, ~m? +# 1885| mu1885_6(Bar2) = ^IndirectMayWriteSideEffect[-1] : &:r1885_1 +# 1886| v1886_1(void) = NoOp : +# 1883| v1883_4(void) = ReturnVoid : +# 1883| v1883_5(void) = AliasedUse : ~m? +# 1883| v1883_6(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 diff --git a/cpp/ql/test/library-tests/pod/isPOD.ql b/cpp/ql/test/library-tests/pod/isPOD.ql index e7860247eb7..77f7e136019 100644 --- a/cpp/ql/test/library-tests/pod/isPOD.ql +++ b/cpp/ql/test/library-tests/pod/isPOD.ql @@ -1,5 +1,5 @@ import cpp from Class c, boolean ispod -where if c.isPOD() then ispod = true else ispod = false +where if c.isPod() then ispod = true else ispod = false select c, ispod diff --git a/cpp/ql/test/library-tests/pod/isPOD03.ql b/cpp/ql/test/library-tests/pod/isPOD03.ql index 42f6eed559f..84f2433f8da 100644 --- a/cpp/ql/test/library-tests/pod/isPOD03.ql +++ b/cpp/ql/test/library-tests/pod/isPOD03.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.PODType03 from Class c, boolean ispod -where if isPODClass03(c) then ispod = true else ispod = false +where if isPodClass03(c) then ispod = true else ispod = false select c, ispod diff --git a/cpp/ql/test/library-tests/sal/sal.ql b/cpp/ql/test/library-tests/sal/sal.ql index eb4908bae9e..52104793d3e 100644 --- a/cpp/ql/test/library-tests/sal/sal.ql +++ b/cpp/ql/test/library-tests/sal/sal.ql @@ -1,4 +1,4 @@ import Microsoft.SAL -from SALAnnotation a +from SalAnnotation a select a, a.getDeclaration() diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 044257ed952..b4035e32b18 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1598,17 +1598,17 @@ postWithInFlow | constmemberaccess.cpp:9:2:9:2 | i [post update] | PostUpdateNode should not be the target of local flow. | | constructorinitializer.cpp:8:4:8:4 | Argument this [post update] | PostUpdateNode should not be the target of local flow. | | constructorinitializer.cpp:8:4:8:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:6:16:6:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:6:5:8:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:6:5:8:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:6:5:8:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:6:5:8:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:7:7:7:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:7:7:7:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:7:7:7:8 | el [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:28:5:28:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:28:5:28:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:28:5:28:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:28:16:28:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:28:5:30:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:28:5:30:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:28:5:30:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:28:5:30:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:28:21:28:21 | (__begin) [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:28:21:28:21 | (__begin) [post update] | PostUpdateNode should not be the target of local flow. | | cpp11.cpp:28:21:28:21 | (__begin) [post update] | PostUpdateNode should not be the target of local flow. | @@ -2644,10 +2644,10 @@ postWithInFlow | stmt_expr.cpp:27:5:27:7 | ptr [post update] | PostUpdateNode should not be the target of local flow. | | stream_it.cpp:4:16:4:30 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | | stream_it.cpp:5:14:5:28 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| stream_it.cpp:11:3:11:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| stream_it.cpp:11:3:11:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| stream_it.cpp:11:3:11:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | -| stream_it.cpp:11:10:11:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| stream_it.cpp:11:3:13:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| stream_it.cpp:11:3:13:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| stream_it.cpp:11:3:13:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | +| stream_it.cpp:11:3:13:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. | | stream_it.cpp:11:16:11:16 | (__range) [post update] | PostUpdateNode should not be the target of local flow. | | stream_it.cpp:11:16:11:16 | (__range) [post update] | PostUpdateNode should not be the target of local flow. | | stream_it.cpp:11:16:11:16 | (__range) [post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/query-tests/Best Practices/Likely Errors/EmptyBlock/EmptyBlock.expected b/cpp/ql/test/query-tests/Best Practices/Likely Errors/EmptyBlock/EmptyBlock.expected index db58438a704..dc572fae9be 100644 --- a/cpp/ql/test/query-tests/Best Practices/Likely Errors/EmptyBlock/EmptyBlock.expected +++ b/cpp/ql/test/query-tests/Best Practices/Likely Errors/EmptyBlock/EmptyBlock.expected @@ -1,3 +1,3 @@ -| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment | -| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment | -| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment | +| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment. | +| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment. | +| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment. | diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected new file mode 100644 index 00000000000..184e893ad16 --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected @@ -0,0 +1,19 @@ +| test.cpp:30:7:30:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:30:7:30:7 | i | i | test.cpp:29:3:29:7 | call to scanf | call to scanf | +| test.cpp:46:7:46:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:46:7:46:7 | i | i | test.cpp:45:3:45:7 | call to scanf | call to scanf | +| test.cpp:63:7:63:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:63:7:63:7 | i | i | test.cpp:62:3:62:7 | call to scanf | call to scanf | +| test.cpp:75:7:75:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:75:7:75:7 | i | i | test.cpp:74:3:74:7 | call to scanf | call to scanf | +| test.cpp:87:7:87:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:87:7:87:7 | i | i | test.cpp:86:3:86:8 | call to fscanf | call to fscanf | +| test.cpp:94:7:94:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:94:7:94:7 | i | i | test.cpp:93:3:93:8 | call to sscanf | call to sscanf | +| test.cpp:143:8:143:8 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:143:8:143:8 | i | i | test.cpp:141:7:141:11 | call to scanf | call to scanf | +| test.cpp:152:8:152:8 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:152:8:152:8 | i | i | test.cpp:150:7:150:11 | call to scanf | call to scanf | +| test.cpp:184:8:184:8 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:184:8:184:8 | i | i | test.cpp:183:7:183:11 | call to scanf | call to scanf | +| test.cpp:203:8:203:8 | j | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:203:8:203:8 | j | j | test.cpp:200:7:200:11 | call to scanf | call to scanf | +| test.cpp:227:9:227:9 | d | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:227:9:227:9 | d | d | test.cpp:225:25:225:29 | call to scanf | call to scanf | +| test.cpp:231:9:231:9 | d | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:231:9:231:9 | d | d | test.cpp:229:14:229:18 | call to scanf | call to scanf | +| test.cpp:243:7:243:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:243:7:243:7 | i | i | test.cpp:242:3:242:7 | call to scanf | call to scanf | +| test.cpp:251:7:251:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:251:7:251:7 | i | i | test.cpp:250:3:250:7 | call to scanf | call to scanf | +| test.cpp:259:7:259:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:259:7:259:7 | i | i | test.cpp:258:3:258:7 | call to scanf | call to scanf | +| test.cpp:271:7:271:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:7:271:7 | i | i | test.cpp:270:3:270:7 | call to scanf | call to scanf | +| test.cpp:281:8:281:12 | ptr_i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:281:8:281:12 | ptr_i | ptr_i | test.cpp:280:3:280:7 | call to scanf | call to scanf | +| test.cpp:289:7:289:7 | i | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:289:7:289:7 | i | i | test.cpp:288:3:288:7 | call to scanf | call to scanf | +| test.cpp:383:25:383:25 | u | $@ is read here, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:383:25:383:25 | u | u | test.cpp:382:6:382:11 | call to sscanf | call to sscanf | diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref new file mode 100644 index 00000000000..97e85b5abbe --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref @@ -0,0 +1 @@ +Critical/MissingCheckScanf.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp new file mode 100644 index 00000000000..e621936dc33 --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp @@ -0,0 +1,387 @@ +typedef struct +{ +} FILE; + +typedef void *locale_t; + +int scanf(const char *format, ...); +int fscanf(FILE *stream, const char *format, ...); +int sscanf(const char *s, const char *format, ...); +int _scanf_l(const char *format, locale_t locale, ...); + +void use(int i); + +void set_by_ref(int &i); +void set_by_ptr(int *i); +bool maybe(); + +FILE *get_a_stream(); +const char *get_a_string(); +extern locale_t get_a_locale(); + +int main() +{ + // --- simple cases --- + + { + int i; + + scanf("%d", &i); + use(i); // BAD: may not have written `i` + } + + { + int i; + + if (scanf("%d", &i) == 1) + { + use(i); // GOOD: checks return value + } + } + + { + int i = 0; + + scanf("%d", &i); + use(i); // BAD. Design choice: already initialized variables shouldn't make a difference. + } + + { + int i; + use(i); // GOOD: only care about uses after scanf call + + if (scanf("%d", &i) == 1) + { + use(i); // GOOD + } + } + + { + int i; // Reused variable + + scanf("%d", &i); + use(i); // BAD + + if (scanf("%d", &i) == 1) + { + use(i); // GOOD + } + } + + { + int i; // Reset variable + + scanf("%d", &i); + use(i); // BAD + + i = 1; + use(i); // GOOD + } + + // --- different scanf functions --- + + { + int i; + + fscanf(get_a_stream(), "%d", &i); + use(i); // BAD: may not have written `i` + } + + { + int i; + + sscanf(get_a_string(), "%d", &i); + use(i); // BAD: may not have written `i` + } + + { + int i; + + if (_scanf_l("%d", get_a_locale(), &i) == 1) + { + use(i); // GOOD + } + } + + // --- different ways of checking --- + + { + int i; + + if (scanf("%d", &i) >= 1) + { + use(i); // GOOD + } + } + + { + int i; + + if (scanf("%d", &i) == 1) + { + use(i); // GOOD + } + } + + { + int i; + + if (0 < scanf("%d", &i)) + { + if (true) + { + use(i); // GOOD + } + } + } + + { + int i; + + if (scanf("%d", &i) != 0) + { + use(i); // BAD: scanf can return EOF + } + } + + { + int i; + + if (scanf("%d", &i) == 0) + { + use(i); // BAD: checks return value incorrectly + } + } + + { + int r; + int i; + + r = scanf("%d", &i); + + if (r >= 1) + { + use(i); // GOOD + } + } + + { + bool b; + int i; + + b = scanf("%d", &i); + + if (b >= 1) + { + use(i); // BAD [NOT DETECTED]: scanf can return EOF (boolifies true) + } + } + + { + int i; + + if (scanf("%d", &i)) + use(i); // BAD + } + + { + int i, j; + + if (scanf("%d %d", &i) >= 2) + { + use(i); // GOOD + use(j); // GOOD: `j` is not a scanf arg, so out of scope of MissingCheckScanf + } + } + + { + int i, j; + + if (scanf("%d %d", &i, &j) >= 1) + { + use(i); // GOOD + use(j); // BAD: checks return value incorrectly + } + } + + { + int i, j; + + if (scanf("%d %d", &i, &j) >= 2) + { + use(i); // GOOD + use(j); // GOOD + } + } + + { + char c[5]; + int d; + + while(maybe()) { + if (maybe()) { + break; + } + else if (maybe() && (scanf("%5c %d", c, &d) == 1)) { // GOOD + use(*(int *)c); // GOOD + use(d); // BAD + } + else if ((scanf("%5c %d", c, &d) == 1) && maybe()) { // GOOD + use(*(int *)c); // GOOD + use(d); // BAD + } + } + } + + // --- different initialization --- + + { + int i; + i = 0; + + scanf("%d", &i); + use(i); // BAD + } + + { + int i; + + set_by_ref(i); + scanf("%d", &i); + use(i); // BAD + } + + { + int i; + + set_by_ptr(&i); + scanf("%d", &i); + use(i); // BAD + } + + { + int i; + + if (maybe()) + { + i = 0; + } + + scanf("%d", &i); + use(i); // BAD: `i` may not have been initialized + } + + // --- different use --- + + { + int i; + int *ptr_i = &i; + + scanf("%d", &i); + use(*ptr_i); // BAD: may not have written `i` + } + + { + int i; + int *ptr_i = &i; + + scanf("%d", ptr_i); + use(i); // BAD: may not have written `*ptr_i` + } + + { + int i; + scanf("%d", &i); + i = 42; + use(i); // GOOD + } + + // --- weird formatting strings --- + + { + int i, j; + + if (sscanf("123", "%n %*d %n", &i, &j) >= 0) + { + use(i); // GOOD (`%n` does not consume input, but writes 0 to i) + use(j); // GOOD (`%n` does not consume input, but writes 3 to j) + } + } + + { + int i; + + if (scanf("%% %d", &i) >= 1) + { + use(i); // GOOD (`%%` does not consume input) + } + } + + { + int i; + + if (scanf("%*d %d", &i) >= 1) + { + use(i); // GOOD (`%*d` does not consume input) + } + } + + { + int d, n; + + if (scanf("%*d %d %n", &d, &n) == 1) { + use(d); // GOOD + use(n); // GOOD + } + } + + { + char substr[32]; + int n; + while (sscanf(get_a_string(), "%31[^:]: %d", substr, &n) == 2) { // GOOD: cycle from write to unguarded access + use(*(int *)substr); // GOOD + use(n); // GOOD + } + } +} + +// --- Non-local cases --- + +bool my_scan_int(int &i) +{ + return scanf("%d", &i) == 1; // GOOD +} + +void my_scan_int_test() +{ + int i; + + use(i); // GOOD: used before scanf + + my_scan_int(i); + use(i); // BAD [NOT DETECTED] + + if (my_scan_int(i)) + { + use(i); // GOOD + } +} + +// --- Can be OK'd given a sufficiently smart analysis --- + +char *my_string_copy() { + static const char SRC_STRING[] = "48656C6C6F"; + static char DST_STRING[] = "....."; + + int len = sizeof(SRC_STRING) - 1; + const char *src = SRC_STRING; + char *ptr = DST_STRING; + + for (int i = 0; i < len; i += 2) { + unsigned int u; + sscanf(src + i, "%2x", &u); + *ptr++ = (char) u; // GOOD [FALSE POSITIVE]? src+i+{0,1} are always valid %x digits, so this should be OK. + } + *ptr++ = 0; + return DST_STRING; +} diff --git a/cpp/ql/test/query-tests/Documentation/CommentedOutCode/CommentedOutCode.expected b/cpp/ql/test/query-tests/Documentation/CommentedOutCode/CommentedOutCode.expected index b7889805514..9b4547cd2cd 100644 --- a/cpp/ql/test/query-tests/Documentation/CommentedOutCode/CommentedOutCode.expected +++ b/cpp/ql/test/query-tests/Documentation/CommentedOutCode/CommentedOutCode.expected @@ -1,20 +1,20 @@ -| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code | -| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code | -| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code | -| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code | -| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code | -| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code | -| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code | -| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code | -| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code | -| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code | -| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code | -| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code | -| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code | -| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code | -| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code | -| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code | -| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code | -| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code | -| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code | -| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code | +| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code. | +| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code. | +| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code. | +| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code. | +| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code. | +| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code. | +| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code. | +| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code. | +| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code. | +| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code. | +| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code. | +| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code. | +| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code. | +| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code. | +| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code. | +| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code. | +| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code. | +| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code. | +| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code. | +| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/BitwiseSignCheck/BitwiseSignCheck.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/BitwiseSignCheck/BitwiseSignCheck.expected index a6d6da31f69..ce1f90c3ed2 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/BitwiseSignCheck/BitwiseSignCheck.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/BitwiseSignCheck/BitwiseSignCheck.expected @@ -1,4 +1,4 @@ -| bsc.cpp:2:10:2:32 | ... > ... | Potential unsafe sign check of a bitwise operation. | -| bsc.cpp:6:10:6:32 | ... > ... | Potential unsafe sign check of a bitwise operation. | -| bsc.cpp:18:10:18:28 | ... > ... | Potential unsafe sign check of a bitwise operation. | -| bsc.cpp:22:10:22:28 | ... < ... | Potential unsafe sign check of a bitwise operation. | +| bsc.cpp:2:10:2:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. | +| bsc.cpp:6:10:6:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. | +| bsc.cpp:18:10:18:28 | ... > ... | Potentially unsafe sign check of a bitwise operation. | +| bsc.cpp:22:10:22:28 | ... < ... | Potentially unsafe sign check of a bitwise operation. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/FloatComparison/FloatComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/FloatComparison/FloatComparison.expected index 6152aa1c475..31fda8e5f89 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/FloatComparison/FloatComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/FloatComparison/FloatComparison.expected @@ -1,4 +1,4 @@ -| c.c:10:5:10:10 | ... == ... | Equality test on floating point values may not behave as expected. | -| c.c:14:5:14:14 | ... == ... | Equality test on floating point values may not behave as expected. | -| c.c:16:5:16:12 | ... == ... | Equality test on floating point values may not behave as expected. | -| c.c:17:5:17:12 | ... == ... | Equality test on floating point values may not behave as expected. | +| c.c:10:5:10:10 | ... == ... | Equality checks on floating point values can yield unexpected results. | +| c.c:14:5:14:14 | ... == ... | Equality checks on floating point values can yield unexpected results. | +| c.c:16:5:16:12 | ... == ... | Equality checks on floating point values can yield unexpected results. | +| c.c:17:5:17:12 | ... == ... | Equality checks on floating point values can yield unexpected results. | diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index 304c8a68b6f..9afe24ed72f 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -413,7 +413,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess["cmd.exe /C dotnet --info"] = 0; actions.RunProcess[@"cmd.exe /C dotnet clean C:\Project\test.csproj"] = 0; actions.RunProcess[@"cmd.exe /C dotnet restore C:\Project\test.csproj"] = 0; - actions.RunProcess[@"cmd.exe /C dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C dotnet build --no-incremental C:\Project\test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project\test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -440,7 +440,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess["dotnet --info"] = 0; actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0; - actions.RunProcess[@"dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0; + actions.RunProcess[@"dotnet build --no-incremental C:\Project/test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project/test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -715,9 +715,9 @@ namespace Semmle.Autobuild.CSharp.Tests public void TestWindowCSharpMsBuild() { actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test1.sln -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test2.sln -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; @@ -746,9 +746,9 @@ namespace Semmle.Autobuild.CSharp.Tests public void TestWindowCSharpMsBuildMultipleSolutions() { actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.csproj -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.csproj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test2.csproj -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.csproj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project\test1.csproj"] = true; actions.FileExists[@"C:\Project\test2.csproj"] = true; @@ -791,7 +791,7 @@ namespace Semmle.Autobuild.CSharp.Tests public void TestWindowCSharpMsBuildFailed() { actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.sln -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 1; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; @@ -817,8 +817,8 @@ namespace Semmle.Autobuild.CSharp.Tests [Fact] public void TestSkipNugetMsBuild() { - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; @@ -862,7 +862,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess["dotnet --info"] = 0; actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0; - actions.RunProcess[@"dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore C:\Project/test.csproj"] = 0; + actions.RunProcess[@"dotnet build --no-incremental --no-restore C:\Project/test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project/test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -894,7 +894,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; - actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental C:\Project/test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists["test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -929,7 +929,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; - actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0; + actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental C:\Project/test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists["test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -960,7 +960,7 @@ namespace Semmle.Autobuild.CSharp.Tests actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0; actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean C:\Project\test.csproj"] = 0; actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore C:\Project\test.csproj"] = 0; - actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0; + actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet build --no-incremental C:\Project\test.csproj"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project\test.csproj"] = true; actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; @@ -1008,7 +1008,7 @@ namespace Semmle.Autobuild.CSharp.Tests { actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\dirs.proj -DisableParallelProcessing"] = 1; actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\dirs.proj -DisableParallelProcessing"] = 0; - actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\dirs.proj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /P:Fu=Bar"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project\a\test.csproj"] = true; actions.FileExists[@"C:\Project\dirs.proj"] = true; @@ -1052,7 +1052,7 @@ namespace Semmle.Autobuild.CSharp.Tests { actions.RunProcess[@"nuget restore C:\Project/dirs.proj -DisableParallelProcessing"] = 1; actions.RunProcess[@"mono C:\Project/.nuget/nuget.exe restore C:\Project/dirs.proj -DisableParallelProcessing"] = 0; - actions.RunProcess[@"msbuild C:\Project/dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 0; + actions.RunProcess[@"msbuild C:\Project/dirs.proj /t:rebuild"] = 0; actions.FileExists["csharp.log"] = true; actions.FileExists[@"C:\Project/a/test.csproj"] = true; actions.FileExists[@"C:\Project/dirs.proj"] = true; diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index 18603809d34..163dbfa1464 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -5,7 +5,6 @@ using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.IO; using Semmle.Util; -using System.Text.RegularExpressions; using Semmle.Autobuild.Shared; namespace Semmle.Autobuild.CSharp @@ -81,9 +80,6 @@ namespace Semmle.Autobuild.CSharp env = null; } - if (env is null) - env = new Dictionary(); - env.Add("UseSharedCompilation", "false"); return f(installDir, env); }); } @@ -245,8 +241,7 @@ namespace Semmle.Autobuild.CSharp Argument("--no-incremental"); return - script.Argument("/p:UseSharedCompilation=false"). - Argument(builder.Options.DotNetArguments). + script.Argument(builder.Options.DotNetArguments). QuoteArgument(projOrSln). Script; } diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 55dbf31ba1b..0afc1da098c 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -98,8 +98,6 @@ namespace Semmle.Autobuild.Shared command.RunCommand(msBuild); command.QuoteArgument(projectOrSolution.FullPath); - command.Argument("/p:UseSharedCompilation=false"); - var target = builder.Options.MsBuildTarget ?? "rebuild"; var platform = builder.Options.MsBuildPlatform ?? (projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null); var configuration = builder.Options.MsBuildConfiguration ?? (projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null); @@ -109,7 +107,6 @@ namespace Semmle.Autobuild.Shared command.Argument(string.Format("/p:Platform=\"{0}\"", platform)); if (configuration is not null) command.Argument(string.Format("/p:Configuration=\"{0}\"", configuration)); - command.Argument("/p:MvcBuildViews=true"); command.Argument(builder.Options.MsBuildArguments); diff --git a/csharp/codeql-extractor.yml b/csharp/codeql-extractor.yml index 4e1fa7934ce..fbf7841eea6 100644 --- a/csharp/codeql-extractor.yml +++ b/csharp/codeql-extractor.yml @@ -35,3 +35,10 @@ options: the code (for example if it uses inaccessible dependencies). type: string pattern: "^(false|true)$" + cil: + title: Whether to enable CIL extraction. + description: > + A value indicating, whether CIL extraction should be enabled. + The default is 'true'. + type: string + pattern: "^(false|true)$" diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv index fd6c64f91d0..6ab77f6aba6 100644 --- a/csharp/documentation/library-coverage/coverage.csv +++ b/csharp/documentation/library-coverage/coverage.csv @@ -9,7 +9,7 @@ Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1 Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3 Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62, Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12, -Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,15, +Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16, Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2 Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1 Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10, @@ -19,10 +19,10 @@ Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,63, Microsoft.Interop,,,27,,,,,,,,,,,,27, Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,1, Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,4, -Microsoft.VisualBasic,,,9,,,,,,,,,,,,5,4 +Microsoft.VisualBasic,,,10,,,,,,,,,,,,5,5 Microsoft.Win32,,,8,,,,,,,,,,,,8, MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,, Newtonsoft.Json,,,91,,,,,,,,,,,,73,18 ServiceStack,194,,7,27,,,,,,75,92,,,,7, -System,43,4,11809,,1,1,1,,4,,33,3,1,3,9867,1942 +System,65,4,12131,,8,8,9,,4,,33,3,1,3,10139,1992 Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,, diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst index 1d3a0a7d5cc..0f3dce2941a 100644 --- a/csharp/documentation/library-coverage/coverage.rst +++ b/csharp/documentation/library-coverage/coverage.rst @@ -8,7 +8,7 @@ C# framework & library support Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting` `ServiceStack `_,"``ServiceStack.*``, ``ServiceStack``",,7,194, - System,"``System.*``, ``System``",4,11809,43,7 - Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,554,138, - Totals,,4,12370,375,7 + System,"``System.*``, ``System``",4,12131,65,7 + Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138, + Totals,,4,12694,397,7 diff --git a/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/old.dbscheme b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/old.dbscheme new file mode 100644 index 00000000000..4ac7d8bcac6 --- /dev/null +++ b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/old.dbscheme @@ -0,0 +1,2064 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/semmlecode.csharp.dbscheme b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..a696c8bae06 --- /dev/null +++ b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/semmlecode.csharp.dbscheme @@ -0,0 +1,2065 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/upgrade.properties b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/upgrade.properties new file mode 100644 index 00000000000..9760a4b01e1 --- /dev/null +++ b/csharp/downgrades/4ac7d8bcac6f664b1e83c858aa71f8dc761cc603/upgrade.properties @@ -0,0 +1,2 @@ +description: Introduce '--cil' flag in the comments. This does not make any changes to the dbscheme. +compatibility: full diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs index 047a8ddb8ae..d4073deee33 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs @@ -13,31 +13,6 @@ namespace Semmle.Extraction.CSharp { Extractor.SetInvariantCulture(); - Console.WriteLine($"Semmle.Extraction.CSharp.Driver: called with {string.Join(", ", args)}"); - - if (args.Length > 0 && args[0] == "--dotnetexec") - { - var compilerRegEx = new Regex(@"csc\.exe|mcs\.exe|csc\.dll", RegexOptions.Compiled); - var cil = args.Length > 1 && args[1] == "--cil"; - for (var i = cil ? 2 : 1; i < args.Length; i++) - { - if (compilerRegEx.IsMatch(args[i])) - { - var argsList = new List(); - if (cil) - argsList.Add("--cil"); - argsList.Add("--compiler"); - argsList.Add(args[i]); - if (i + 1 < args.Length) - argsList.AddRange(args[(i + 1)..]); - return (int)Extractor.Run(argsList.ToArray()); - } - } - - Console.WriteLine($"Semmle.Extraction.CSharp.Driver: not a compiler invocation"); - return 0; - } - return (int)Extractor.Run(args); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs index 6266eb09f93..8ee0cae1fd2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs @@ -56,7 +56,6 @@ namespace Semmle.Extraction.CSharp.Standalone CSharp.Extractor.SetInvariantCulture(); var options = Options.Create(args); - // options.CIL = true; // To do: Enable this if (options.Help) { diff --git a/csharp/extractor/Semmle.Extraction.Tests/Options.cs b/csharp/extractor/Semmle.Extraction.Tests/Options.cs index 2637eb3d5f4..026bc80c114 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Options.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Options.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.Tests { options = CSharp.Options.CreateWithEnvironment(Array.Empty()); Assert.True(options.Cache); - Assert.False(options.CIL); + Assert.True(options.CIL); Assert.Null(options.Framework); Assert.Null(options.CompilerName); Assert.Empty(options.CompilerArguments); @@ -51,10 +51,20 @@ namespace Semmle.Extraction.Tests [Fact] public void CIL() { - options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" }); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); Assert.True(options.CIL); - options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil", "--nocil" }); + + Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "false"); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); Assert.False(options.CIL); + + Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "true"); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); + Assert.True(options.CIL); + + Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", null); + options = CSharp.Options.CreateWithEnvironment(Array.Empty()); + Assert.True(options.CIL); } [Fact] @@ -121,22 +131,6 @@ namespace Semmle.Extraction.Tests Assert.Equal("foo", options.Framework); } - [Fact] - public void EnvironmentVariables() - { - Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--cil c"); - options = CSharp.Options.CreateWithEnvironment(new string[] { "a", "b" }); - Assert.True(options.CIL); - Assert.Equal("a", options.CompilerArguments[0]); - Assert.Equal("b", options.CompilerArguments[1]); - Assert.Equal("c", options.CompilerArguments[2]); - - Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", ""); - Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--nocil"); - options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" }); - Assert.False(options.CIL); - } - [Fact] public void StandaloneDefaults() { diff --git a/csharp/extractor/Semmle.Extraction/Options.cs b/csharp/extractor/Semmle.Extraction/Options.cs index bef37be1d45..afd4b2db7eb 100644 --- a/csharp/extractor/Semmle.Extraction/Options.cs +++ b/csharp/extractor/Semmle.Extraction/Options.cs @@ -28,7 +28,7 @@ namespace Semmle.Extraction /// /// Holds if CIL should be extracted. /// - public bool CIL { get; private set; } = false; + public bool CIL { get; private set; } = true; /// /// Holds if assemblies shouldn't be extracted twice. @@ -50,7 +50,6 @@ namespace Semmle.Extraction /// public bool QlTest { get; private set; } = false; - /// /// The compression algorithm used for trap files. /// @@ -73,6 +72,9 @@ namespace Semmle.Extraction return true; } return false; + case "cil": + CIL = Boolean.Parse(value); + return true; default: return false; } @@ -97,9 +99,6 @@ namespace Semmle.Extraction case "cache": Cache = value; return true; - case "cil": - CIL = value; - return true; case "pdb": PDB = value; CIL = true; diff --git a/csharp/extractor/Semmle.Util/CommandLineOptions.cs b/csharp/extractor/Semmle.Util/CommandLineOptions.cs index 5531155d5be..34917ae6bcd 100644 --- a/csharp/extractor/Semmle.Util/CommandLineOptions.cs +++ b/csharp/extractor/Semmle.Util/CommandLineOptions.cs @@ -17,7 +17,7 @@ namespace Semmle.Util bool HandleOption(string key, string value); /// - /// Handle a flag of the form "--cil" or "--nocil" + /// Handle a flag of the form "--cache" or "--nocache" /// /// The name of the flag. This is case sensitive. /// True if set, or false if prefixed by "--no" @@ -40,6 +40,7 @@ namespace Semmle.Util public static class OptionsExtensions { + private static readonly string[] ExtractorOptions = new[] { "trap_compression", "cil" }; private static string? GetExtractorOption(string name) => Environment.GetEnvironmentVariable($"CODEQL_EXTRACTOR_CSHARP_OPTION_{name.ToUpper()}"); @@ -47,12 +48,14 @@ namespace Semmle.Util { var extractorOptions = new List(); - var trapCompression = GetExtractorOption("trap_compression"); - if (!string.IsNullOrEmpty(trapCompression)) + foreach (var option in ExtractorOptions) { - extractorOptions.Add($"--trap_compression:{trapCompression}"); + var value = GetExtractorOption(option); + if (!string.IsNullOrEmpty(value)) + { + extractorOptions.Add($"--{option}:{value}"); + } } - return extractorOptions; } diff --git a/csharp/ql/campaigns/Solorigate/src/ModifiedFnvFunctionDetection.ql b/csharp/ql/campaigns/Solorigate/src/ModifiedFnvFunctionDetection.ql index e9f81596e04..5e4a47f7ec0 100644 --- a/csharp/ql/campaigns/Solorigate/src/ModifiedFnvFunctionDetection.ql +++ b/csharp/ql/campaigns/Solorigate/src/ModifiedFnvFunctionDetection.ql @@ -15,7 +15,7 @@ import experimental.code.csharp.Cryptography.NonCryptographicHashes from Variable v, Literal l, LoopStmt loop, Expr additional_xor where - maybeUsedInFNVFunction(v, _, _, loop) and + maybeUsedInFnvFunction(v, _, _, loop) and ( exists(BitwiseXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 | loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and diff --git a/csharp/ql/consistency-queries/SsaConsistency.ql b/csharp/ql/consistency-queries/SsaConsistency.ql index ee231828279..71f88bf2ab0 100644 --- a/csharp/ql/consistency-queries/SsaConsistency.ql +++ b/csharp/ql/consistency-queries/SsaConsistency.ql @@ -1,8 +1,8 @@ import csharp -import semmle.code.csharp.dataflow.internal.SsaImplCommon::Consistency +import semmle.code.csharp.dataflow.internal.SsaImpl::Consistency as Consistency import Ssa -class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { +class MyRelevantDefinition extends Consistency::RelevantDefinition, Ssa::Definition { override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { @@ -10,6 +10,14 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { } } +query predicate nonUniqueDef = Consistency::nonUniqueDef/4; + +query predicate readWithoutDef = Consistency::readWithoutDef/3; + +query predicate deadDef = Consistency::deadDef/2; + +query predicate notDominatedByDef = Consistency::notDominatedByDef/4; + query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) { // Local variables in C# must be initialized before every use, so uninitialized // local variables should not have an SSA definition, as that would imply that diff --git a/csharp/ql/integration-tests/all-platforms/dotnet_build/Program.cs b/csharp/ql/integration-tests/all-platforms/dotnet_build/Program.cs new file mode 100644 index 00000000000..e9708d0b5d2 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/dotnet_build/Program.cs @@ -0,0 +1 @@ +Console.WriteLine(args[0]); diff --git a/csharp/ql/integration-tests/all-platforms/dotnet_build/dotnet_build.csproj b/csharp/ql/integration-tests/all-platforms/dotnet_build/dotnet_build.csproj new file mode 100644 index 00000000000..74abf5c9766 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/dotnet_build/dotnet_build.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py new file mode 100644 index 00000000000..2568768ad6b --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py @@ -0,0 +1,3 @@ +from create_database_utils import * + +run_codeql_database_create(['dotnet build'], test_db="default-db", db=None, lang="csharp") diff --git a/csharp/ql/integration-tests/all-platforms/qlpack.yml b/csharp/ql/integration-tests/all-platforms/qlpack.yml new file mode 100644 index 00000000000..f1531efffb2 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/qlpack.yml @@ -0,0 +1,2 @@ +libraryPathDependencies: + - codeql-csharp diff --git a/csharp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md b/csharp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md new file mode 100644 index 00000000000..efdaf85f2ed --- /dev/null +++ b/csharp/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states. \ No newline at end of file diff --git a/csharp/ql/lib/change-notes/2022-09-12-uppercase.md b/csharp/ql/lib/change-notes/2022-09-12-uppercase.md new file mode 100644 index 00000000000..996861f1c2c --- /dev/null +++ b/csharp/ql/lib/change-notes/2022-09-12-uppercase.md @@ -0,0 +1,5 @@ +--- +category: deprecated +--- +* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. + The old name still exists as a deprecated alias. \ No newline at end of file diff --git a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll index 03585e32a77..28de629816d 100644 --- a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -13,7 +13,7 @@ private import semmle.code.csharp.dataflow.TaintTracking2 predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop) { callable = loop.getEnclosingCallable() and ( - maybeUsedInFNVFunction(v, xor, mul, loop) or + maybeUsedInFnvFunction(v, xor, mul, loop) or maybeUsedInElfHashFunction(v, xor, mul, loop) ) } @@ -23,7 +23,7 @@ predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Exp * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression * followed by a multiplication `mul` expression. */ -predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) { +predicate maybeUsedInFnvFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) { exists(Expr e1, Expr e2 | e1.getAChild*() = v.getAnAccess() and e2.getAChild*() = v.getAnAccess() and @@ -37,6 +37,9 @@ predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopS loop.getAChild*() = xor.getEnclosingStmt() } +/** DEPRECATED: Alias for maybeUsedInFnvFunction */ +deprecated predicate maybeUsedInFNVFunction = maybeUsedInFnvFunction/4; + /** * Holds if the arguments are used in a way that resembles an Elf-Hash hash function * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 0af84d51ff3..7716eb77741 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -5,3 +5,5 @@ dbscheme: semmlecode.csharp.dbscheme extractor: csharp library: true upgrades: upgrades +dependencies: + codeql/ssa: 0.0.1 diff --git a/csharp/ql/lib/semmle/code/cil/CallableReturns.qll b/csharp/ql/lib/semmle/code/cil/CallableReturns.qll index 6a86ef72170..4cd46c10941 100644 --- a/csharp/ql/lib/semmle/code/cil/CallableReturns.qll +++ b/csharp/ql/lib/semmle/code/cil/CallableReturns.qll @@ -56,7 +56,7 @@ private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) { /** Holds if expression `expr` always evaluates to non-null. */ private predicate alwaysNotNullExpr(Expr expr) { - expr instanceof Opcodes::Newobj + expr instanceof Opcodes::NewObj or expr instanceof Literal and not expr instanceof NullLiteral or diff --git a/csharp/ql/lib/semmle/code/cil/Instructions.qll b/csharp/ql/lib/semmle/code/cil/Instructions.qll index 91bc1f37ea6..7d425594b8d 100644 --- a/csharp/ql/lib/semmle/code/cil/Instructions.qll +++ b/csharp/ql/lib/semmle/code/cil/Instructions.qll @@ -766,7 +766,7 @@ module Opcodes { } /** A `newobj` instruction. */ - class Newobj extends Call, @cil_newobj { + class NewObj extends Call, @cil_newobj { override string getOpcodeName() { result = "newobj" } override int getPushCount() { result = 1 } @@ -788,6 +788,9 @@ module Opcodes { } } + /** DEPRECATED: Alias for NewObj */ + deprecated class Newobj = NewObj; + /** An `initobj` instruction. */ class Initobj extends Instruction, @cil_initobj { override string getOpcodeName() { result = "initobj" } @@ -847,10 +850,13 @@ module Opcodes { } /** A `rethrow` instruction. */ - class Rethrow extends Throw, @cil_rethrow { + class ReThrow extends Throw, @cil_rethrow { override string getOpcodeName() { result = "rethrow" } } + /** DEPRECATED: Alias for ReThrow */ + deprecated class Rethrow = ReThrow; + /** A `ldlen` instruction. */ class Ldlen extends UnaryExpr, @cil_ldlen { override string getOpcodeName() { result = "ldlen" } diff --git a/csharp/ql/lib/semmle/code/cil/Ssa.qll b/csharp/ql/lib/semmle/code/cil/Ssa.qll index 229925f6d08..50338d3284d 100644 --- a/csharp/ql/lib/semmle/code/cil/Ssa.qll +++ b/csharp/ql/lib/semmle/code/cil/Ssa.qll @@ -8,13 +8,12 @@ private import CIL * Provides classes for working with static single assignment (SSA) form. */ module Ssa { - private import internal.SsaImplCommon as SsaImpl - private import internal.SsaImpl + private import internal.SsaImpl as SsaImpl /** An SSA definition. */ class Definition extends SsaImpl::Definition { /** Gets a read of this SSA definition. */ - final ReadAccess getARead() { result = getARead(this) } + final ReadAccess getARead() { result = SsaImpl::getARead(this) } /** Gets the underlying variable update, if any. */ final VariableUpdate getVariableUpdate() { @@ -25,11 +24,11 @@ module Ssa { } /** Gets a first read of this SSA definition. */ - final ReadAccess getAFirstRead() { result = getAFirstRead(this) } + final ReadAccess getAFirstRead() { result = SsaImpl::getAFirstRead(this) } /** Holds if `first` and `second` are adjacent reads of this SSA definition. */ final predicate hasAdjacentReads(ReadAccess first, ReadAccess second) { - hasAdjacentReads(this, first, second) + SsaImpl::hasAdjacentReads(this, first, second) } private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() } @@ -52,7 +51,7 @@ module Ssa { final override Location getLocation() { result = this.getBasicBlock().getLocation() } /** Gets an input to this phi node. */ - final Definition getAnInput() { result = getAPhiInput(this) } + final Definition getAnInput() { result = SsaImpl::getAPhiInput(this) } /** * Holds if if `def` is an input to this phi node, and a reference to `def` at @@ -60,7 +59,7 @@ module Ssa { * other references. */ final predicate hasLastInputRef(Definition def, BasicBlock bb, int i) { - hasLastInputRef(this, def, bb, i) + SsaImpl::hasLastInputRef(this, def, bb, i) } } } diff --git a/csharp/ql/lib/semmle/code/cil/internal/SsaImpl.qll b/csharp/ql/lib/semmle/code/cil/internal/SsaImpl.qll index 593c877b9af..9ca724cb08d 100644 --- a/csharp/ql/lib/semmle/code/cil/internal/SsaImpl.qll +++ b/csharp/ql/lib/semmle/code/cil/internal/SsaImpl.qll @@ -1,8 +1,40 @@ -private import semmle.code.cil.CIL -private import SsaImplCommon +private import cil +private import codeql.ssa.Ssa as SsaImplCommon + +private module SsaInput implements SsaImplCommon::InputSig { + class BasicBlock = CIL::BasicBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock = CIL::ExitBasicBlock; + + class SourceVariable = CIL::StackVariable; + + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + forceCachingInSameStage() and + exists(CIL::VariableUpdate vu | + vu.updatesAt(bb, i) and + v = vu.getVariable() and + certain = true + ) + } + + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(CIL::ReadAccess ra | bb.getNode(i) = ra | + ra.getTarget() = v and + certain = true + ) + } +} + +import SsaImplCommon::Make cached private module Cached { + private import CIL + cached predicate forceCachingInSameStage() { any() } diff --git a/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll b/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll deleted file mode 100644 index 659940def50..00000000000 --- a/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Provides a language-independent implementation of static single assignment - * (SSA) form. - */ - -private import SsaImplSpecific - -private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } - -/** - * Liveness analysis (based on source variables) to restrict the size of the - * SSA representation. - */ -private module Liveness { - /** - * A classification of variable references into reads (of a given kind) and - * (certain or uncertain) writes. - */ - private newtype TRefKind = - Read(boolean certain) { certain in [false, true] } or - Write(boolean certain) { certain in [false, true] } - - private class RefKind extends TRefKind { - string toString() { - exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") - or - exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") - } - - int getOrder() { - this = Read(_) and - result = 0 - or - this = Write(_) and - result = 1 - } - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. - */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) - or - exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) - } - - private newtype OrderedRefIndex = - MkOrderedRefIndex(int i, int tag) { - exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) - } - - private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { - ref(bb, i, v, k) and - result = MkOrderedRefIndex(i, ord) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of - * basic block `bb`, which has the given reference kind `k`. - * - * Reads are considered before writes when they happen at the same index. - */ - private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - refOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedRefIndex res | - res = refOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - private int maxRefRank(BasicBlock bb, SourceVariable v) { - result = refRank(bb, _, v, _) and - not result + 1 = refRank(bb, _, v, _) - } - - predicate lastRefIsRead(BasicBlock bb, SourceVariable v) { - maxRefRank(bb, v) = refRank(bb, _, v, Read(_)) - } - - /** - * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` - * that is either a read or a certain write. - */ - private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { - result = - min(int r, RefKind k | - r = refRank(bb, _, v, k) and - k != Write(false) - | - r - ) - } - - /** - * Holds if source variable `v` is live at the beginning of basic block `bb`. - */ - predicate liveAtEntry(BasicBlock bb, SourceVariable v) { - // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) - or - // There is no certain write to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(firstReadOrCertainWrite(bb, v)) and - liveAtExit(bb, v) - } - - /** - * Holds if source variable `v` is live at the end of basic block `bb`. - */ - predicate liveAtExit(BasicBlock bb, SourceVariable v) { - liveAtEntry(getABasicBlockSuccessor(bb), v) - } - - /** - * Holds if variable `v` is live in basic block `bb` at index `i`. - * The rank of `i` is `rnk` as defined by `refRank()`. - */ - private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { - exists(RefKind kind | rnk = refRank(bb, i, v, kind) | - rnk = maxRefRank(bb, v) and - liveAtExit(bb, v) - or - ref(bb, i, v, kind) and - kind = Read(_) - or - exists(RefKind nextKind | - liveAtRank(bb, _, v, rnk + 1) and - rnk + 1 = refRank(bb, _, v, nextKind) and - nextKind != Write(true) - ) - ) - } - - /** - * Holds if variable `v` is live after the (certain or uncertain) write at - * index `i` inside basic block `bb`. - */ - predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { - exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) - } -} - -private import Liveness - -/** - * Holds if `df` is in the dominance frontier of `bb`. - * - * This is equivalent to: - * - * ```ql - * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and - * not bb = getImmediateBasicBlockDominator+(df) - * ``` - */ -private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) - or - exists(BasicBlock prev | inDominanceFrontier(prev, df) | - bb = getImmediateBasicBlockDominator(prev) and - not bb = getImmediateBasicBlockDominator(df) - ) -} - -/** - * Holds if `bb` is in the dominance frontier of a block containing a - * definition of `v`. - */ -pragma[noinline] -private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock defbb, Definition def | - def.definesAt(v, defbb, _) and - inDominanceFrontier(defbb, bb) - ) -} - -cached -newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - -private module SsaDefReaches { - newtype TSsaRefKind = - SsaActualRead() or - SsaPhiRead() or - SsaDef() - - class SsaRead = SsaActualRead or SsaPhiRead; - - /** - * A classification of SSA variable references into reads and definitions. - */ - class SsaRefKind extends TSsaRefKind { - string toString() { - this = SsaActualRead() and - result = "SsaActualRead" - or - this = SsaPhiRead() and - result = "SsaPhiRead" - or - this = SsaDef() and - result = "SsaDef" - } - - int getOrder() { - this instanceof SsaRead and - result = 0 - or - this = SsaDef() and - result = 1 - } - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). - * - * Unlike `Liveness::ref`, this includes `phi` nodes. - */ - pragma[nomagic] - predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v, _) and - k = SsaActualRead() - or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() - } - - private newtype OrderedSsaRefIndex = - MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } - - private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { - ssaRef(bb, i, v, k) and - result = MkOrderedSsaRefIndex(i, k) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: - * - * ```ql - * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 - * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 - * ``` - * - * Reads are considered before writes when they happen at the same index. - */ - int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - ssaRefOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedSsaRefIndex res | - res = ssaRefOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - int maxSsaRefRank(BasicBlock bb, SourceVariable v) { - result = ssaRefRank(bb, _, v, _) and - not result + 1 = ssaRefRank(bb, _, v, _) - } - - /** - * Holds if the SSA definition `def` reaches rank index `rnk` in its own - * basic block `bb`. - */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { - exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) - ) - or - ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) - } - - /** - * Holds if the SSA definition of `v` at `def` reaches index `i` in the same - * basic block `bb`, without crossing another SSA definition of `v`. - */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { - exists(int rnk | - ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) - ) - } - - /** - * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. - */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, k) and - ( - ssaDefReachesRead(_, def, bb, i) - or - def.definesAt(_, bb, i) - ) - } - - /** - * Holds if the reference to `def` at index `i` in basic block `bb` is the - * last reference to `v` inside `bb`. - */ - pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) - } - - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { - exists(ssaDefRank(def, v, bb, _, k)) - } - - pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ - * predecessor of `bb2`, and the underlying variable for `def` is neither read - * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. - */ - pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and - bb2 = getABasicBlockSuccessor(bb1) - or - exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and - ssaDefReachesThroughBlock(def, mid) and - bb2 = getABasicBlockSuccessor(mid) - ) - } - - pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) - } - - pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) - or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) - ) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) - } - - pragma[nomagic] - predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 - } - - /** - * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, - * and `v` is neither read nor written in any block on the path between `bb` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | - not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) - ) - or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) - ) - } -} - -predicate phiReadExposedForTesting = phiRead/2; - -private import SsaDefReaches - -pragma[nomagic] -predicate liveThrough(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches the end of basic - * block `bb`, at which point it is still live, without crossing another - * SSA definition of `v`. - */ -pragma[nomagic] -predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { - exists(int last | - last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and - ssaDefReachesRank(bb, def, last, v) and - liveAtExit(bb, v) - ) - or - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. - */ -pragma[nomagic] -predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. - */ -pragma[nomagic] -predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(v, def, bb, i) - or - ssaRef(bb, i, v, any(SsaRead k)) and - ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read - * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a - * path between them without any read of `def`. - */ -pragma[nomagic] -predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and - bb2 = bb1 - ) - or - lastSsaRef(def, _, bb1, i1) and - defAdjacentRead(def, bb1, bb2, i2) -} - -pragma[noinline] -private predicate adjacentDefRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v -) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -private predicate adjacentDefReachesRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - ssaRef(bb1, i1, v, SsaDef()) - or - variableRead(bb1, i1, v, true) - ) - or - exists(BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `adjacentDefRead`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, true) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA definition - * `def`. The reference is last because it can reach another write `next`, - * without passing through another read or write. - */ -pragma[nomagic] -predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps - lastSsaRef(def, v, bb, i) and - exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and - 1 = ssaDefRank(next, v, bb2, _, SsaDef()) - ) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an immediately preceding definition of uncertain definition - * `def`. Since `def` is uncertain, the value from the preceding definition might - * still be valid. - */ -pragma[nomagic] -predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) -} - -private predicate adjacentDefReachesUncertainRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, false) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA - * definition `def`. - * - * That is, the node can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. - */ -pragma[nomagic] -predicate lastRef(Definition def, BasicBlock bb, int i) { - // Can reach another definition - lastRefRedef(def, bb, i, _) - or - exists(SourceVariable v | lastSsaRef(def, v, bb, i) | - // Can reach exit directly - bb instanceof ExitBasicBlock - or - // Can reach a block using one or more steps, where `def` is no longer live - varBlockReachesExit(def, bb) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { - lastRef(def, bb, i) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** A static single assignment (SSA) definition. */ -class Definition extends TDefinition { - /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { this.definesAt(result, _, _) } - - /** - * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. - * Phi nodes are considered to be at index `-1`, while normal variable writes - * are at the index of the control flow node they wrap. - */ - final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { - this = TWriteDef(v, bb, i) - or - this = TPhiNode(v, bb) and i = -1 - } - - /** Gets the basic block to which this SSA definition belongs. */ - final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - - /** Gets a textual representation of this SSA definition. */ - string toString() { none() } -} - -/** An SSA definition that corresponds to a write. */ -class WriteDefinition extends Definition, TWriteDef { - private SourceVariable v; - private BasicBlock bb; - private int i; - - WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } -} - -/** A phi node. */ -class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } -} - -/** - * An SSA definition that represents an uncertain update of the underlying - * source variable. - */ -class UncertainWriteDefinition extends WriteDefinition { - UncertainWriteDefinition() { - exists(SourceVariable v, BasicBlock bb, int i | - this.definesAt(v, bb, i) and - variableWrite(bb, i, v, false) - ) - } -} - -/** Provides a set of consistency queries. */ -module Consistency { - abstract class RelevantDefinition extends Definition { - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); - } - - query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefReachesRead(v, def, bb, i) and - not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) - } - - query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { - variableRead(bb, i, v, _) and - not ssaDefReachesRead(v, _, bb, i) - } - - query predicate deadDef(RelevantDefinition def, SourceVariable v) { - v = def.getSourceVariable() and - not ssaDefReachesRead(_, def, _, _) and - not phiHasInputFromBlock(_, def, _) and - not uncertainWriteDefinitionInput(_, def) - } - - query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | - ssaDefReachesReadWithinBlock(v, def, bb, i) and - (bb != bbDef or i < iDef) - or - ssaDefReachesRead(v, def, bb, i) and - not ssaDefReachesReadWithinBlock(v, def, bb, i) and - not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) - ) - } -} diff --git a/csharp/ql/lib/semmle/code/cil/internal/SsaImplSpecific.qll b/csharp/ql/lib/semmle/code/cil/internal/SsaImplSpecific.qll deleted file mode 100644 index 94b4812d996..00000000000 --- a/csharp/ql/lib/semmle/code/cil/internal/SsaImplSpecific.qll +++ /dev/null @@ -1,30 +0,0 @@ -/** Provides the CIL specific parameters for `SsaImplCommon.qll`. */ - -private import cil -private import SsaImpl - -class BasicBlock = CIL::BasicBlock; - -BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } - -BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - -class ExitBasicBlock = CIL::ExitBasicBlock; - -class SourceVariable = CIL::StackVariable; - -predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { - forceCachingInSameStage() and - exists(CIL::VariableUpdate vu | - vu.updatesAt(bb, i) and - v = vu.getVariable() and - certain = true - ) -} - -predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { - exists(CIL::ReadAccess ra | bb.getNode(i) = ra | - ra.getTarget() = v and - certain = true - ) -} diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll index 08e5925ad50..44ff56706a7 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -192,8 +192,7 @@ class BasicBlock extends TBasicBlockStart { * Gets the basic block that immediately dominates this basic block, if any. * * That is, all paths reaching this basic block from some entry point - * basic block must go through the result, which is an immediate basic block - * predecessor of this basic block. + * basic block must go through the result. * * Example: * @@ -207,8 +206,7 @@ class BasicBlock extends TBasicBlockStart { * * The basic block starting on line 2 is an immediate dominator of * the basic block online 4 (all paths from the entry point of `M` - * to `return s.Length;` must go through the null check, and the null check - * is an immediate predecessor of `return s.Length;`). + * to `return s.Length;` must go through the null check. */ BasicBlock getImmediateDominator() { bbIDominates(result, this) } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll index 5ac313651d7..73d19171a52 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll @@ -6,26 +6,158 @@ import csharp * scope variables. */ module PreSsa { - import pressa.SsaImplSpecific - private import pressa.SsaImplCommon as SsaImpl + private import AssignableDefinitions + private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl + private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks + private import codeql.ssa.Ssa as SsaImplCommon + + private predicate definitionAt( + AssignableDefinition def, SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v + ) { + bb.getElement(i) = def.getExpr() and + v = def.getTarget() and + // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` + not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | + second.getAssignment() = first.getAssignment() and + second.getEvaluationOrder() > first.getEvaluationOrder() and + second.getTarget() = v + ) + or + def.(ImplicitParameterDefinition).getParameter() = v and + exists(Callable c | v = c.getAParameter() | + scopeFirst(c, bb) and + i = -1 + ) + } + + predicate implicitEntryDef(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v) { + not v instanceof LocalScopeVariable and + c = v.getACallable() and + scopeFirst(c, bb) + } + + module SsaInput implements SsaImplCommon::InputSig { + class BasicBlock = PreBasicBlocks::PreBasicBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock extends BasicBlock { + ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) } + } + + /** Holds if `a` is assigned in non-constructor callable `c`. */ + pragma[nomagic] + private predicate assignableDefinition(Assignable a, Callable c) { + exists(AssignableDefinition def | def.getTarget() = a | + c = def.getEnclosingCallable() and + not c instanceof Constructor + ) + } + + /** Holds if `a` is accessed in callable `c`. */ + pragma[nomagic] + private predicate assignableAccess(Assignable a, Callable c) { + exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) + } + + pragma[nomagic] + private predicate assignableNoCapturing(Assignable a, Callable c) { + assignableAccess(a, c) and + /* + * The code below is equivalent to + * ```ql + * not exists(Callable other | assignableDefinition(a, other) | other != c) + * ``` + * but it avoids a Cartesian product in the compiler generated antijoin + * predicate. + */ + + ( + not assignableDefinition(a, _) + or + c = unique(Callable c0 | assignableDefinition(a, c0) | c0) + ) + } + + pragma[noinline] + private predicate assignableNoComplexQualifiers(Assignable a) { + forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance()) + } + + /** + * A simple assignable. Either a local scope variable or a field/property + * that behaves like a local scope variable. + */ + class SourceVariable extends Assignable { + private Callable c; + + SourceVariable() { + ( + this instanceof LocalScopeVariable + or + this = any(Field f | not f.isVolatile()) + or + this = any(TrivialProperty tp | not tp.isOverridableOrImplementable()) + ) and + assignableNoCapturing(this, c) and + assignableNoComplexQualifiers(this) + } + + /** Gets a callable in which this simple assignable can be analyzed. */ + Callable getACallable() { result = c } + } + + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableDefinition def | + definitionAt(def, bb, i, v) and + if def.getTargetAccess().isRefArgument() then certain = false else certain = true + ) + or + exists(Callable c | + implicitEntryDef(c, bb, v) and + i = -1 and + certain = true + ) + } + + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableRead read | + read = bb.getElement(i) and + read.getTarget() = v and + certain = true + ) + or + v = + any(LocalScopeVariable lsv | + lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and + i = bb.length() and + (lsv.isRef() or v.(Parameter).isOut()) and + certain = false + ) + } + } + + private module SsaImpl = SsaImplCommon::Make; class Definition extends SsaImpl::Definition { final AssignableRead getARead() { - exists(BasicBlock bb, int i | + exists(SsaInput::BasicBlock bb, int i | SsaImpl::ssaDefReachesRead(_, this, bb, i) and result = bb.getElement(i) ) } final AssignableDefinition getDefinition() { - exists(BasicBlock bb, int i, SourceVariable v | + exists(SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v | this.definesAt(v, bb, i) and definitionAt(result, bb, i, v) ) } final AssignableRead getAFirstRead() { - exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 | this.definesAt(_, bb1, i1) and SsaImpl::adjacentDefRead(this, bb1, i1, bb2, i2) and result = bb2.getElement(i2) @@ -42,14 +174,14 @@ module PreSsa { not result instanceof PhiNode } - final predicate isLiveAtEndOfBlock(BasicBlock bb) { + final predicate isLiveAtEndOfBlock(SsaInput::BasicBlock bb) { SsaImpl::ssaDefReachesEndOfBlock(bb, this, _) } Location getLocation() { result = this.getDefinition().getLocation() or - exists(Callable c, BasicBlock bb, SourceVariable v | + exists(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v | this.definesAt(v, bb, -1) and implicitEntryDef(c, bb, v) and result = c.getLocation() @@ -64,9 +196,9 @@ module PreSsa { } predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) { - exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 | read1 = bb1.getElement(i1) and - variableRead(bb1, i1, _, true) and + SsaInput::variableRead(bb1, i1, _, true) and SsaImpl::adjacentDefRead(_, bb1, i1, bb2, i2) and read2 = bb2.getElement(i2) ) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll deleted file mode 100644 index 659940def50..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Provides a language-independent implementation of static single assignment - * (SSA) form. - */ - -private import SsaImplSpecific - -private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } - -/** - * Liveness analysis (based on source variables) to restrict the size of the - * SSA representation. - */ -private module Liveness { - /** - * A classification of variable references into reads (of a given kind) and - * (certain or uncertain) writes. - */ - private newtype TRefKind = - Read(boolean certain) { certain in [false, true] } or - Write(boolean certain) { certain in [false, true] } - - private class RefKind extends TRefKind { - string toString() { - exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") - or - exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") - } - - int getOrder() { - this = Read(_) and - result = 0 - or - this = Write(_) and - result = 1 - } - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. - */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) - or - exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) - } - - private newtype OrderedRefIndex = - MkOrderedRefIndex(int i, int tag) { - exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) - } - - private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { - ref(bb, i, v, k) and - result = MkOrderedRefIndex(i, ord) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of - * basic block `bb`, which has the given reference kind `k`. - * - * Reads are considered before writes when they happen at the same index. - */ - private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - refOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedRefIndex res | - res = refOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - private int maxRefRank(BasicBlock bb, SourceVariable v) { - result = refRank(bb, _, v, _) and - not result + 1 = refRank(bb, _, v, _) - } - - predicate lastRefIsRead(BasicBlock bb, SourceVariable v) { - maxRefRank(bb, v) = refRank(bb, _, v, Read(_)) - } - - /** - * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` - * that is either a read or a certain write. - */ - private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { - result = - min(int r, RefKind k | - r = refRank(bb, _, v, k) and - k != Write(false) - | - r - ) - } - - /** - * Holds if source variable `v` is live at the beginning of basic block `bb`. - */ - predicate liveAtEntry(BasicBlock bb, SourceVariable v) { - // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) - or - // There is no certain write to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(firstReadOrCertainWrite(bb, v)) and - liveAtExit(bb, v) - } - - /** - * Holds if source variable `v` is live at the end of basic block `bb`. - */ - predicate liveAtExit(BasicBlock bb, SourceVariable v) { - liveAtEntry(getABasicBlockSuccessor(bb), v) - } - - /** - * Holds if variable `v` is live in basic block `bb` at index `i`. - * The rank of `i` is `rnk` as defined by `refRank()`. - */ - private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { - exists(RefKind kind | rnk = refRank(bb, i, v, kind) | - rnk = maxRefRank(bb, v) and - liveAtExit(bb, v) - or - ref(bb, i, v, kind) and - kind = Read(_) - or - exists(RefKind nextKind | - liveAtRank(bb, _, v, rnk + 1) and - rnk + 1 = refRank(bb, _, v, nextKind) and - nextKind != Write(true) - ) - ) - } - - /** - * Holds if variable `v` is live after the (certain or uncertain) write at - * index `i` inside basic block `bb`. - */ - predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { - exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) - } -} - -private import Liveness - -/** - * Holds if `df` is in the dominance frontier of `bb`. - * - * This is equivalent to: - * - * ```ql - * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and - * not bb = getImmediateBasicBlockDominator+(df) - * ``` - */ -private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) - or - exists(BasicBlock prev | inDominanceFrontier(prev, df) | - bb = getImmediateBasicBlockDominator(prev) and - not bb = getImmediateBasicBlockDominator(df) - ) -} - -/** - * Holds if `bb` is in the dominance frontier of a block containing a - * definition of `v`. - */ -pragma[noinline] -private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock defbb, Definition def | - def.definesAt(v, defbb, _) and - inDominanceFrontier(defbb, bb) - ) -} - -cached -newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - -private module SsaDefReaches { - newtype TSsaRefKind = - SsaActualRead() or - SsaPhiRead() or - SsaDef() - - class SsaRead = SsaActualRead or SsaPhiRead; - - /** - * A classification of SSA variable references into reads and definitions. - */ - class SsaRefKind extends TSsaRefKind { - string toString() { - this = SsaActualRead() and - result = "SsaActualRead" - or - this = SsaPhiRead() and - result = "SsaPhiRead" - or - this = SsaDef() and - result = "SsaDef" - } - - int getOrder() { - this instanceof SsaRead and - result = 0 - or - this = SsaDef() and - result = 1 - } - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). - * - * Unlike `Liveness::ref`, this includes `phi` nodes. - */ - pragma[nomagic] - predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v, _) and - k = SsaActualRead() - or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() - } - - private newtype OrderedSsaRefIndex = - MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } - - private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { - ssaRef(bb, i, v, k) and - result = MkOrderedSsaRefIndex(i, k) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: - * - * ```ql - * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 - * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 - * ``` - * - * Reads are considered before writes when they happen at the same index. - */ - int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - ssaRefOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedSsaRefIndex res | - res = ssaRefOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - int maxSsaRefRank(BasicBlock bb, SourceVariable v) { - result = ssaRefRank(bb, _, v, _) and - not result + 1 = ssaRefRank(bb, _, v, _) - } - - /** - * Holds if the SSA definition `def` reaches rank index `rnk` in its own - * basic block `bb`. - */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { - exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) - ) - or - ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) - } - - /** - * Holds if the SSA definition of `v` at `def` reaches index `i` in the same - * basic block `bb`, without crossing another SSA definition of `v`. - */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { - exists(int rnk | - ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) - ) - } - - /** - * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. - */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, k) and - ( - ssaDefReachesRead(_, def, bb, i) - or - def.definesAt(_, bb, i) - ) - } - - /** - * Holds if the reference to `def` at index `i` in basic block `bb` is the - * last reference to `v` inside `bb`. - */ - pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) - } - - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { - exists(ssaDefRank(def, v, bb, _, k)) - } - - pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ - * predecessor of `bb2`, and the underlying variable for `def` is neither read - * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. - */ - pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and - bb2 = getABasicBlockSuccessor(bb1) - or - exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and - ssaDefReachesThroughBlock(def, mid) and - bb2 = getABasicBlockSuccessor(mid) - ) - } - - pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) - } - - pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) - or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) - ) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) - } - - pragma[nomagic] - predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 - } - - /** - * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, - * and `v` is neither read nor written in any block on the path between `bb` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | - not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) - ) - or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) - ) - } -} - -predicate phiReadExposedForTesting = phiRead/2; - -private import SsaDefReaches - -pragma[nomagic] -predicate liveThrough(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches the end of basic - * block `bb`, at which point it is still live, without crossing another - * SSA definition of `v`. - */ -pragma[nomagic] -predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { - exists(int last | - last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and - ssaDefReachesRank(bb, def, last, v) and - liveAtExit(bb, v) - ) - or - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. - */ -pragma[nomagic] -predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. - */ -pragma[nomagic] -predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(v, def, bb, i) - or - ssaRef(bb, i, v, any(SsaRead k)) and - ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read - * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a - * path between them without any read of `def`. - */ -pragma[nomagic] -predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and - bb2 = bb1 - ) - or - lastSsaRef(def, _, bb1, i1) and - defAdjacentRead(def, bb1, bb2, i2) -} - -pragma[noinline] -private predicate adjacentDefRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v -) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -private predicate adjacentDefReachesRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - ssaRef(bb1, i1, v, SsaDef()) - or - variableRead(bb1, i1, v, true) - ) - or - exists(BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `adjacentDefRead`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, true) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA definition - * `def`. The reference is last because it can reach another write `next`, - * without passing through another read or write. - */ -pragma[nomagic] -predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps - lastSsaRef(def, v, bb, i) and - exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and - 1 = ssaDefRank(next, v, bb2, _, SsaDef()) - ) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an immediately preceding definition of uncertain definition - * `def`. Since `def` is uncertain, the value from the preceding definition might - * still be valid. - */ -pragma[nomagic] -predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) -} - -private predicate adjacentDefReachesUncertainRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, false) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA - * definition `def`. - * - * That is, the node can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. - */ -pragma[nomagic] -predicate lastRef(Definition def, BasicBlock bb, int i) { - // Can reach another definition - lastRefRedef(def, bb, i, _) - or - exists(SourceVariable v | lastSsaRef(def, v, bb, i) | - // Can reach exit directly - bb instanceof ExitBasicBlock - or - // Can reach a block using one or more steps, where `def` is no longer live - varBlockReachesExit(def, bb) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { - lastRef(def, bb, i) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** A static single assignment (SSA) definition. */ -class Definition extends TDefinition { - /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { this.definesAt(result, _, _) } - - /** - * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. - * Phi nodes are considered to be at index `-1`, while normal variable writes - * are at the index of the control flow node they wrap. - */ - final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { - this = TWriteDef(v, bb, i) - or - this = TPhiNode(v, bb) and i = -1 - } - - /** Gets the basic block to which this SSA definition belongs. */ - final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - - /** Gets a textual representation of this SSA definition. */ - string toString() { none() } -} - -/** An SSA definition that corresponds to a write. */ -class WriteDefinition extends Definition, TWriteDef { - private SourceVariable v; - private BasicBlock bb; - private int i; - - WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } -} - -/** A phi node. */ -class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } -} - -/** - * An SSA definition that represents an uncertain update of the underlying - * source variable. - */ -class UncertainWriteDefinition extends WriteDefinition { - UncertainWriteDefinition() { - exists(SourceVariable v, BasicBlock bb, int i | - this.definesAt(v, bb, i) and - variableWrite(bb, i, v, false) - ) - } -} - -/** Provides a set of consistency queries. */ -module Consistency { - abstract class RelevantDefinition extends Definition { - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); - } - - query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefReachesRead(v, def, bb, i) and - not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) - } - - query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { - variableRead(bb, i, v, _) and - not ssaDefReachesRead(v, _, bb, i) - } - - query predicate deadDef(RelevantDefinition def, SourceVariable v) { - v = def.getSourceVariable() and - not ssaDefReachesRead(_, def, _, _) and - not phiHasInputFromBlock(_, def, _) and - not uncertainWriteDefinitionInput(_, def) - } - - query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | - ssaDefReachesReadWithinBlock(v, def, bb, i) and - (bb != bbDef or i < iDef) - or - ssaDefReachesRead(v, def, bb, i) and - not ssaDefReachesReadWithinBlock(v, def, bb, i) and - not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll deleted file mode 100644 index ad64c38973a..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll +++ /dev/null @@ -1,130 +0,0 @@ -/** Provides the C# specific parameters for `SsaImplCommon.qll`. */ - -private import csharp -private import AssignableDefinitions -private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks -private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl - -class BasicBlock = PreBasicBlocks::PreBasicBlock; - -BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } - -BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - -class ExitBasicBlock extends BasicBlock { - ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) } -} - -/** Holds if `a` is assigned in non-constructor callable `c`. */ -pragma[nomagic] -private predicate assignableDefinition(Assignable a, Callable c) { - exists(AssignableDefinition def | def.getTarget() = a | - c = def.getEnclosingCallable() and - not c instanceof Constructor - ) -} - -/** Holds if `a` is accessed in callable `c`. */ -pragma[nomagic] -private predicate assignableAccess(Assignable a, Callable c) { - exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) -} - -pragma[nomagic] -private predicate assignableNoCapturing(Assignable a, Callable c) { - assignableAccess(a, c) and - /* - * The code below is equivalent to - * ```ql - * not exists(Callable other | assignableDefinition(a, other) | other != c) - * ``` - * but it avoids a Cartesian product in the compiler generated antijoin - * predicate. - */ - - ( - not assignableDefinition(a, _) - or - c = unique(Callable c0 | assignableDefinition(a, c0) | c0) - ) -} - -pragma[noinline] -private predicate assignableNoComplexQualifiers(Assignable a) { - forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance()) -} - -/** - * A simple assignable. Either a local scope variable or a field/property - * that behaves like a local scope variable. - */ -class SourceVariable extends Assignable { - private Callable c; - - SourceVariable() { - ( - this instanceof LocalScopeVariable - or - this = any(Field f | not f.isVolatile()) - or - this = any(TrivialProperty tp | not tp.isOverridableOrImplementable()) - ) and - assignableNoCapturing(this, c) and - assignableNoComplexQualifiers(this) - } - - /** Gets a callable in which this simple assignable can be analyzed. */ - Callable getACallable() { result = c } -} - -predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) { - bb.getElement(i) = def.getExpr() and - v = def.getTarget() and - // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` - not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | - second.getAssignment() = first.getAssignment() and - second.getEvaluationOrder() > first.getEvaluationOrder() and - second.getTarget() = v - ) - or - def.(ImplicitParameterDefinition).getParameter() = v and - exists(Callable c | v = c.getAParameter() | - scopeFirst(c, bb) and - i = -1 - ) -} - -predicate implicitEntryDef(Callable c, BasicBlock bb, SourceVariable v) { - not v instanceof LocalScopeVariable and - c = v.getACallable() and - scopeFirst(c, bb) -} - -predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { - exists(AssignableDefinition def | - definitionAt(def, bb, i, v) and - if def.getTargetAccess().isRefArgument() then certain = false else certain = true - ) - or - exists(Callable c | - implicitEntryDef(c, bb, v) and - i = -1 and - certain = true - ) -} - -predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { - exists(AssignableRead read | - read = bb.getElement(i) and - read.getTarget() = v and - certain = true - ) - or - v = - any(LocalScopeVariable lsv | - lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and - i = bb.length() and - (lsv.isRef() or v.(Parameter).isOut()) and - certain = false - ) -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 9285ba2f4a7..8227501f841 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -12,6 +12,8 @@ * `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance` * - Negative Summaries: * `namespace; type; name; signature; provenance` + * A negative summary is used to indicate that there is no flow via a callable. + * * The interpretation of a row is similar to API-graphs with a left-to-right * reading. * 1. The `namespace` column selects a namespace. @@ -100,6 +102,7 @@ private module Frameworks { private import semmle.code.csharp.frameworks.ServiceStack private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.frameworks.System + private import semmle.code.csharp.frameworks.system.CodeDom private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Concurrent private import semmle.code.csharp.frameworks.system.collections.Generic @@ -108,6 +111,7 @@ private module Frameworks { private import semmle.code.csharp.frameworks.system.collections.Specialized private import semmle.code.csharp.frameworks.system.ComponentModel private import semmle.code.csharp.frameworks.system.componentmodel.Design + private import semmle.code.csharp.frameworks.system.Configuration private import semmle.code.csharp.frameworks.system.Data private import semmle.code.csharp.frameworks.system.data.Common private import semmle.code.csharp.frameworks.system.Diagnostics @@ -119,6 +123,7 @@ private module Frameworks { private import semmle.code.csharp.frameworks.system.IO private import semmle.code.csharp.frameworks.system.io.Compression private import semmle.code.csharp.frameworks.system.runtime.CompilerServices + private import semmle.code.csharp.frameworks.system.Security private import semmle.code.csharp.frameworks.system.security.Cryptography private import semmle.code.csharp.frameworks.system.security.cryptography.X509Certificates private import semmle.code.csharp.frameworks.system.Text diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll index 281523a2fbd..cb737200a02 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll @@ -4,19 +4,74 @@ import csharp * Provides a simple SSA implementation for local scope variables. */ module BaseSsa { - import basessa.SsaImplSpecific - private import basessa.SsaImplCommon as SsaImpl + private import AssignableDefinitions + private import codeql.ssa.Ssa as SsaImplCommon + + /** + * Holds if the `i`th node of basic block `bb` is assignable definition `def`, + * targeting local scope variable `v`. + */ + private predicate definitionAt( + AssignableDefinition def, ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v + ) { + bb.getNode(i) = def.getAControlFlowNode() and + v = def.getTarget() and + // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` + not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | + second.getAssignment() = first.getAssignment() and + second.getEvaluationOrder() > first.getEvaluationOrder() and + second.getTarget() = v + ) + } + + private module SsaInput implements SsaImplCommon::InputSig { + class BasicBlock = ControlFlow::BasicBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { + result = bb.getImmediateDominator() + } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock; + + pragma[noinline] + private Callable getAnAssigningCallable(LocalScopeVariable v) { + result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable() + } + + class SourceVariable extends LocalScopeVariable { + SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) } + } + + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableDefinition def | + definitionAt(def, bb, i, v) and + if def.isCertain() then certain = true else certain = false + ) + } + + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableRead read | + read.getAControlFlowNode() = bb.getNode(i) and + read.getTarget() = v and + certain = true + ) + } + } + + private module SsaImpl = SsaImplCommon::Make; class Definition extends SsaImpl::Definition { final AssignableRead getARead() { - exists(BasicBlock bb, int i | + exists(ControlFlow::BasicBlock bb, int i | SsaImpl::ssaDefReachesRead(_, this, bb, i) and result.getAControlFlowNode() = bb.getNode(i) ) } final AssignableDefinition getDefinition() { - exists(BasicBlock bb, int i, SourceVariable v | + exists(ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v | this.definesAt(v, bb, i) and definitionAt(result, bb, i, v) ) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index e00fc952e1c..d857cdaa359 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -226,15 +226,6 @@ module Public { none() } - /** - * Holds if values stored inside `content` are cleared on objects passed as - * arguments at position `pos` to this callable. - * - * TODO: Remove once all languages support `WithoutContent` tokens. - */ - pragma[nomagic] - predicate clearsContent(ParameterPosition pos, ContentSet content) { none() } - /** * Holds if the summary is auto generated. */ @@ -328,23 +319,6 @@ module Private { SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and preservesValue = preservesValue1.booleanAnd(preservesValue2) ) - or - exists(ParameterPosition ppos, ContentSet cs | - c.clearsContent(ppos, cs) and - input = SummaryComponentStack::push(SummaryComponent::withoutContent(cs), output) and - output = SummaryComponentStack::argument(ppos) and - preservesValue = true - ) - } - - private class MkClearStack extends RequiredSummaryComponentStack { - override predicate required(SummaryComponent head, SummaryComponentStack tail) { - exists(SummarizedCallable sc, ParameterPosition ppos, ContentSet cs | - sc.clearsContent(ppos, cs) and - head = SummaryComponent::withoutContent(cs) and - tail = SummaryComponentStack::argument(ppos) - ) - } } /** @@ -945,8 +919,7 @@ module Private { AccessPath inSpec, AccessPath outSpec, string kind ) { summaryElement(this, inSpec, outSpec, kind, true) and - not summaryElement(this, _, _, _, false) and - not this.clearsContent(_, _) + not summaryElement(this, _, _, _, false) } private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll index 620c3a7a410..864fda40cf7 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll @@ -163,6 +163,10 @@ bindingset[c] SummaryComponent interpretComponentSpecific(AccessPathToken c) { c = "Element" and result = SummaryComponent::content(any(ElementContent ec)) or + c = "WithoutElement" and result = SummaryComponent::withoutContent(any(ElementContent ec)) + or + c = "WithElement" and result = SummaryComponent::withContent(any(ElementContent ec)) + or // Qualified names may contain commas,such as in `Tuple<,>`, so get the entire argument list // rather than an individual argument. exists(Field f | @@ -199,6 +203,10 @@ private string getContentSpecificCsv(Content c) { string getComponentSpecificCsv(SummaryComponent sc) { exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecificCsv(c)) or + exists(Content c | sc = TWithoutContentSummaryComponent(c) and result = "WithoutElement") + or + exists(Content c | sc = TWithContentSummaryComponent(c) and result = "WithElement") + or exists(ReturnKind rk | sc = TReturnSummaryComponent(rk) and result = "ReturnValue[" + rk + "]" and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll index 7528d47db91..0655ffee6f9 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -3,7 +3,53 @@ */ import csharp -import SsaImplCommon +private import codeql.ssa.Ssa as SsaImplCommon +private import AssignableDefinitions + +private module SsaInput implements SsaImplCommon::InputSig { + class BasicBlock = ControlFlow::BasicBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock; + + class SourceVariable = Ssa::SourceVariable; + + /** + * Holds if the `i`th node of basic block `bb` is a (potential) write to source + * variable `v`. The Boolean `certain` indicates whether the write is certain. + * + * This includes implicit writes via calls. + */ + predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) { + variableWriteDirect(bb, i, v, certain) + or + variableWriteQualifier(bb, i, v, certain) + or + updatesNamedFieldOrProp(bb, i, _, v, _) and + certain = false + or + updatesCapturedVariable(bb, i, _, v, _, _) and + certain = false + } + + /** + * Holds if the `i`th of basic block `bb` reads source variable `v`. + * + * This includes implicit reads via calls. + */ + predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) { + variableReadActual(bb, i, v) and + certain = true + or + variableReadPseudo(bb, i, v) and + certain = false + } +} + +import SsaImplCommon::Make /** * Holds if the `i`th node of basic block `bb` reads source variable `v`. @@ -805,24 +851,6 @@ private module CapturedVariableImpl { } } -/** - * Holds if the `i`th node of basic block `bb` is a (potential) write to source - * variable `v`. The Boolean `certain` indicates whether the write is certain. - * - * This includes implicit writes via calls. - */ -predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) { - variableWriteDirect(bb, i, v, certain) - or - variableWriteQualifier(bb, i, v, certain) - or - updatesNamedFieldOrProp(bb, i, _, v, _) and - certain = false - or - updatesCapturedVariable(bb, i, _, v, _, _) and - certain = false -} - /** * Liveness analysis to restrict the size of the SSA representation for * captured variables. @@ -1039,19 +1067,6 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou capturedReadIn(bb, i, v, _, _, _) } -/** - * Holds if the `i`th of basic block `bb` reads source variable `v`. - * - * This includes implicit reads via calls. - */ -predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) { - variableReadActual(bb, i, v) and - certain = true - or - variableReadPseudo(bb, i, v) and - certain = false -} - cached private module Cached { cached @@ -1151,7 +1166,7 @@ private module Cached { predicate variableWriteQualifier( ControlFlow::BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v, boolean certain ) { - variableWrite(bb, i, v.getQualifier(), certain) and + SsaInput::variableWrite(bb, i, v.getQualifier(), certain) and // Eliminate corner case where a call definition can overlap with a // qualifier definition: if method `M` updates field `F`, then a call // to `M` is both an update of `x.M` and `x.M.M`, so the former call diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll deleted file mode 100644 index 659940def50..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Provides a language-independent implementation of static single assignment - * (SSA) form. - */ - -private import SsaImplSpecific - -private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } - -/** - * Liveness analysis (based on source variables) to restrict the size of the - * SSA representation. - */ -private module Liveness { - /** - * A classification of variable references into reads (of a given kind) and - * (certain or uncertain) writes. - */ - private newtype TRefKind = - Read(boolean certain) { certain in [false, true] } or - Write(boolean certain) { certain in [false, true] } - - private class RefKind extends TRefKind { - string toString() { - exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") - or - exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") - } - - int getOrder() { - this = Read(_) and - result = 0 - or - this = Write(_) and - result = 1 - } - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. - */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) - or - exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) - } - - private newtype OrderedRefIndex = - MkOrderedRefIndex(int i, int tag) { - exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) - } - - private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { - ref(bb, i, v, k) and - result = MkOrderedRefIndex(i, ord) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of - * basic block `bb`, which has the given reference kind `k`. - * - * Reads are considered before writes when they happen at the same index. - */ - private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - refOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedRefIndex res | - res = refOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - private int maxRefRank(BasicBlock bb, SourceVariable v) { - result = refRank(bb, _, v, _) and - not result + 1 = refRank(bb, _, v, _) - } - - predicate lastRefIsRead(BasicBlock bb, SourceVariable v) { - maxRefRank(bb, v) = refRank(bb, _, v, Read(_)) - } - - /** - * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` - * that is either a read or a certain write. - */ - private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { - result = - min(int r, RefKind k | - r = refRank(bb, _, v, k) and - k != Write(false) - | - r - ) - } - - /** - * Holds if source variable `v` is live at the beginning of basic block `bb`. - */ - predicate liveAtEntry(BasicBlock bb, SourceVariable v) { - // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) - or - // There is no certain write to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(firstReadOrCertainWrite(bb, v)) and - liveAtExit(bb, v) - } - - /** - * Holds if source variable `v` is live at the end of basic block `bb`. - */ - predicate liveAtExit(BasicBlock bb, SourceVariable v) { - liveAtEntry(getABasicBlockSuccessor(bb), v) - } - - /** - * Holds if variable `v` is live in basic block `bb` at index `i`. - * The rank of `i` is `rnk` as defined by `refRank()`. - */ - private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { - exists(RefKind kind | rnk = refRank(bb, i, v, kind) | - rnk = maxRefRank(bb, v) and - liveAtExit(bb, v) - or - ref(bb, i, v, kind) and - kind = Read(_) - or - exists(RefKind nextKind | - liveAtRank(bb, _, v, rnk + 1) and - rnk + 1 = refRank(bb, _, v, nextKind) and - nextKind != Write(true) - ) - ) - } - - /** - * Holds if variable `v` is live after the (certain or uncertain) write at - * index `i` inside basic block `bb`. - */ - predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { - exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) - } -} - -private import Liveness - -/** - * Holds if `df` is in the dominance frontier of `bb`. - * - * This is equivalent to: - * - * ```ql - * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and - * not bb = getImmediateBasicBlockDominator+(df) - * ``` - */ -private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) - or - exists(BasicBlock prev | inDominanceFrontier(prev, df) | - bb = getImmediateBasicBlockDominator(prev) and - not bb = getImmediateBasicBlockDominator(df) - ) -} - -/** - * Holds if `bb` is in the dominance frontier of a block containing a - * definition of `v`. - */ -pragma[noinline] -private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock defbb, Definition def | - def.definesAt(v, defbb, _) and - inDominanceFrontier(defbb, bb) - ) -} - -cached -newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - -private module SsaDefReaches { - newtype TSsaRefKind = - SsaActualRead() or - SsaPhiRead() or - SsaDef() - - class SsaRead = SsaActualRead or SsaPhiRead; - - /** - * A classification of SSA variable references into reads and definitions. - */ - class SsaRefKind extends TSsaRefKind { - string toString() { - this = SsaActualRead() and - result = "SsaActualRead" - or - this = SsaPhiRead() and - result = "SsaPhiRead" - or - this = SsaDef() and - result = "SsaDef" - } - - int getOrder() { - this instanceof SsaRead and - result = 0 - or - this = SsaDef() and - result = 1 - } - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). - * - * Unlike `Liveness::ref`, this includes `phi` nodes. - */ - pragma[nomagic] - predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v, _) and - k = SsaActualRead() - or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() - } - - private newtype OrderedSsaRefIndex = - MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } - - private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { - ssaRef(bb, i, v, k) and - result = MkOrderedSsaRefIndex(i, k) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: - * - * ```ql - * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 - * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 - * ``` - * - * Reads are considered before writes when they happen at the same index. - */ - int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - ssaRefOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedSsaRefIndex res | - res = ssaRefOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - int maxSsaRefRank(BasicBlock bb, SourceVariable v) { - result = ssaRefRank(bb, _, v, _) and - not result + 1 = ssaRefRank(bb, _, v, _) - } - - /** - * Holds if the SSA definition `def` reaches rank index `rnk` in its own - * basic block `bb`. - */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { - exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) - ) - or - ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) - } - - /** - * Holds if the SSA definition of `v` at `def` reaches index `i` in the same - * basic block `bb`, without crossing another SSA definition of `v`. - */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { - exists(int rnk | - ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) - ) - } - - /** - * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. - */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, k) and - ( - ssaDefReachesRead(_, def, bb, i) - or - def.definesAt(_, bb, i) - ) - } - - /** - * Holds if the reference to `def` at index `i` in basic block `bb` is the - * last reference to `v` inside `bb`. - */ - pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) - } - - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { - exists(ssaDefRank(def, v, bb, _, k)) - } - - pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ - * predecessor of `bb2`, and the underlying variable for `def` is neither read - * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. - */ - pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and - bb2 = getABasicBlockSuccessor(bb1) - or - exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and - ssaDefReachesThroughBlock(def, mid) and - bb2 = getABasicBlockSuccessor(mid) - ) - } - - pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) - } - - pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) - or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) - ) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) - } - - pragma[nomagic] - predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 - } - - /** - * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, - * and `v` is neither read nor written in any block on the path between `bb` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | - not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) - ) - or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) - ) - } -} - -predicate phiReadExposedForTesting = phiRead/2; - -private import SsaDefReaches - -pragma[nomagic] -predicate liveThrough(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches the end of basic - * block `bb`, at which point it is still live, without crossing another - * SSA definition of `v`. - */ -pragma[nomagic] -predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { - exists(int last | - last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and - ssaDefReachesRank(bb, def, last, v) and - liveAtExit(bb, v) - ) - or - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. - */ -pragma[nomagic] -predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. - */ -pragma[nomagic] -predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(v, def, bb, i) - or - ssaRef(bb, i, v, any(SsaRead k)) and - ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read - * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a - * path between them without any read of `def`. - */ -pragma[nomagic] -predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and - bb2 = bb1 - ) - or - lastSsaRef(def, _, bb1, i1) and - defAdjacentRead(def, bb1, bb2, i2) -} - -pragma[noinline] -private predicate adjacentDefRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v -) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -private predicate adjacentDefReachesRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - ssaRef(bb1, i1, v, SsaDef()) - or - variableRead(bb1, i1, v, true) - ) - or - exists(BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `adjacentDefRead`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, true) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA definition - * `def`. The reference is last because it can reach another write `next`, - * without passing through another read or write. - */ -pragma[nomagic] -predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps - lastSsaRef(def, v, bb, i) and - exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and - 1 = ssaDefRank(next, v, bb2, _, SsaDef()) - ) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an immediately preceding definition of uncertain definition - * `def`. Since `def` is uncertain, the value from the preceding definition might - * still be valid. - */ -pragma[nomagic] -predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) -} - -private predicate adjacentDefReachesUncertainRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, false) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA - * definition `def`. - * - * That is, the node can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. - */ -pragma[nomagic] -predicate lastRef(Definition def, BasicBlock bb, int i) { - // Can reach another definition - lastRefRedef(def, bb, i, _) - or - exists(SourceVariable v | lastSsaRef(def, v, bb, i) | - // Can reach exit directly - bb instanceof ExitBasicBlock - or - // Can reach a block using one or more steps, where `def` is no longer live - varBlockReachesExit(def, bb) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { - lastRef(def, bb, i) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** A static single assignment (SSA) definition. */ -class Definition extends TDefinition { - /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { this.definesAt(result, _, _) } - - /** - * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. - * Phi nodes are considered to be at index `-1`, while normal variable writes - * are at the index of the control flow node they wrap. - */ - final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { - this = TWriteDef(v, bb, i) - or - this = TPhiNode(v, bb) and i = -1 - } - - /** Gets the basic block to which this SSA definition belongs. */ - final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - - /** Gets a textual representation of this SSA definition. */ - string toString() { none() } -} - -/** An SSA definition that corresponds to a write. */ -class WriteDefinition extends Definition, TWriteDef { - private SourceVariable v; - private BasicBlock bb; - private int i; - - WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } -} - -/** A phi node. */ -class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } -} - -/** - * An SSA definition that represents an uncertain update of the underlying - * source variable. - */ -class UncertainWriteDefinition extends WriteDefinition { - UncertainWriteDefinition() { - exists(SourceVariable v, BasicBlock bb, int i | - this.definesAt(v, bb, i) and - variableWrite(bb, i, v, false) - ) - } -} - -/** Provides a set of consistency queries. */ -module Consistency { - abstract class RelevantDefinition extends Definition { - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); - } - - query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefReachesRead(v, def, bb, i) and - not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) - } - - query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { - variableRead(bb, i, v, _) and - not ssaDefReachesRead(v, _, bb, i) - } - - query predicate deadDef(RelevantDefinition def, SourceVariable v) { - v = def.getSourceVariable() and - not ssaDefReachesRead(_, def, _, _) and - not phiHasInputFromBlock(_, def, _) and - not uncertainWriteDefinitionInput(_, def) - } - - query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | - ssaDefReachesReadWithinBlock(v, def, bb, i) and - (bb != bbDef or i < iDef) - or - ssaDefReachesRead(v, def, bb, i) and - not ssaDefReachesReadWithinBlock(v, def, bb, i) and - not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll deleted file mode 100644 index a929e23a942..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll +++ /dev/null @@ -1,19 +0,0 @@ -/** Provides the C# specific parameters for `SsaImplCommon.qll`. */ - -private import csharp -private import AssignableDefinitions -private import SsaImpl as SsaImpl - -class BasicBlock = ControlFlow::BasicBlock; - -BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } - -BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - -class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock; - -class SourceVariable = Ssa::SourceVariable; - -predicate variableWrite = SsaImpl::variableWrite/4; - -predicate variableRead = SsaImpl::variableRead/4; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll deleted file mode 100644 index 659940def50..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Provides a language-independent implementation of static single assignment - * (SSA) form. - */ - -private import SsaImplSpecific - -private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } - -/** - * Liveness analysis (based on source variables) to restrict the size of the - * SSA representation. - */ -private module Liveness { - /** - * A classification of variable references into reads (of a given kind) and - * (certain or uncertain) writes. - */ - private newtype TRefKind = - Read(boolean certain) { certain in [false, true] } or - Write(boolean certain) { certain in [false, true] } - - private class RefKind extends TRefKind { - string toString() { - exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") - or - exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") - } - - int getOrder() { - this = Read(_) and - result = 0 - or - this = Write(_) and - result = 1 - } - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. - */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) - or - exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) - } - - private newtype OrderedRefIndex = - MkOrderedRefIndex(int i, int tag) { - exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) - } - - private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { - ref(bb, i, v, k) and - result = MkOrderedRefIndex(i, ord) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of - * basic block `bb`, which has the given reference kind `k`. - * - * Reads are considered before writes when they happen at the same index. - */ - private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - refOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedRefIndex res | - res = refOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - private int maxRefRank(BasicBlock bb, SourceVariable v) { - result = refRank(bb, _, v, _) and - not result + 1 = refRank(bb, _, v, _) - } - - predicate lastRefIsRead(BasicBlock bb, SourceVariable v) { - maxRefRank(bb, v) = refRank(bb, _, v, Read(_)) - } - - /** - * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` - * that is either a read or a certain write. - */ - private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { - result = - min(int r, RefKind k | - r = refRank(bb, _, v, k) and - k != Write(false) - | - r - ) - } - - /** - * Holds if source variable `v` is live at the beginning of basic block `bb`. - */ - predicate liveAtEntry(BasicBlock bb, SourceVariable v) { - // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) - or - // There is no certain write to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(firstReadOrCertainWrite(bb, v)) and - liveAtExit(bb, v) - } - - /** - * Holds if source variable `v` is live at the end of basic block `bb`. - */ - predicate liveAtExit(BasicBlock bb, SourceVariable v) { - liveAtEntry(getABasicBlockSuccessor(bb), v) - } - - /** - * Holds if variable `v` is live in basic block `bb` at index `i`. - * The rank of `i` is `rnk` as defined by `refRank()`. - */ - private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { - exists(RefKind kind | rnk = refRank(bb, i, v, kind) | - rnk = maxRefRank(bb, v) and - liveAtExit(bb, v) - or - ref(bb, i, v, kind) and - kind = Read(_) - or - exists(RefKind nextKind | - liveAtRank(bb, _, v, rnk + 1) and - rnk + 1 = refRank(bb, _, v, nextKind) and - nextKind != Write(true) - ) - ) - } - - /** - * Holds if variable `v` is live after the (certain or uncertain) write at - * index `i` inside basic block `bb`. - */ - predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { - exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) - } -} - -private import Liveness - -/** - * Holds if `df` is in the dominance frontier of `bb`. - * - * This is equivalent to: - * - * ```ql - * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and - * not bb = getImmediateBasicBlockDominator+(df) - * ``` - */ -private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) - or - exists(BasicBlock prev | inDominanceFrontier(prev, df) | - bb = getImmediateBasicBlockDominator(prev) and - not bb = getImmediateBasicBlockDominator(df) - ) -} - -/** - * Holds if `bb` is in the dominance frontier of a block containing a - * definition of `v`. - */ -pragma[noinline] -private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock defbb, Definition def | - def.definesAt(v, defbb, _) and - inDominanceFrontier(defbb, bb) - ) -} - -cached -newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - -private module SsaDefReaches { - newtype TSsaRefKind = - SsaActualRead() or - SsaPhiRead() or - SsaDef() - - class SsaRead = SsaActualRead or SsaPhiRead; - - /** - * A classification of SSA variable references into reads and definitions. - */ - class SsaRefKind extends TSsaRefKind { - string toString() { - this = SsaActualRead() and - result = "SsaActualRead" - or - this = SsaPhiRead() and - result = "SsaPhiRead" - or - this = SsaDef() and - result = "SsaDef" - } - - int getOrder() { - this instanceof SsaRead and - result = 0 - or - this = SsaDef() and - result = 1 - } - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). - * - * Unlike `Liveness::ref`, this includes `phi` nodes. - */ - pragma[nomagic] - predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v, _) and - k = SsaActualRead() - or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() - } - - private newtype OrderedSsaRefIndex = - MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } - - private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { - ssaRef(bb, i, v, k) and - result = MkOrderedSsaRefIndex(i, k) and - ord = k.getOrder() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: - * - * ```ql - * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 - * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 - * ``` - * - * Reads are considered before writes when they happen at the same index. - */ - int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - ssaRefOrd(bb, i, v, k, _) = - rank[result](int j, int ord, OrderedSsaRefIndex res | - res = ssaRefOrd(bb, j, v, _, ord) - | - res order by j, ord - ) - } - - int maxSsaRefRank(BasicBlock bb, SourceVariable v) { - result = ssaRefRank(bb, _, v, _) and - not result + 1 = ssaRefRank(bb, _, v, _) - } - - /** - * Holds if the SSA definition `def` reaches rank index `rnk` in its own - * basic block `bb`. - */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { - exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) - ) - or - ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) - } - - /** - * Holds if the SSA definition of `v` at `def` reaches index `i` in the same - * basic block `bb`, without crossing another SSA definition of `v`. - */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { - exists(int rnk | - ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) - ) - } - - /** - * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. - */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, k) and - ( - ssaDefReachesRead(_, def, bb, i) - or - def.definesAt(_, bb, i) - ) - } - - /** - * Holds if the reference to `def` at index `i` in basic block `bb` is the - * last reference to `v` inside `bb`. - */ - pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) - } - - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { - exists(ssaDefRank(def, v, bb, _, k)) - } - - pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ - * predecessor of `bb2`, and the underlying variable for `def` is neither read - * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. - */ - pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and - bb2 = getABasicBlockSuccessor(bb1) - or - exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and - ssaDefReachesThroughBlock(def, mid) and - bb2 = getABasicBlockSuccessor(mid) - ) - } - - pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) - } - - pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) - or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) - ) - } - - /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) - } - - pragma[nomagic] - predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 - } - - /** - * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, - * and `v` is neither read nor written in any block on the path between `bb` - * and `bb2`. - */ - pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | - not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) - ) - or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) - ) - } -} - -predicate phiReadExposedForTesting = phiRead/2; - -private import SsaDefReaches - -pragma[nomagic] -predicate liveThrough(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches the end of basic - * block `bb`, at which point it is still live, without crossing another - * SSA definition of `v`. - */ -pragma[nomagic] -predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { - exists(int last | - last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and - ssaDefReachesRank(bb, def, last, v) and - liveAtExit(bb, v) - ) - or - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. - */ -pragma[nomagic] -predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. - */ -pragma[nomagic] -predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(v, def, bb, i) - or - ssaRef(bb, i, v, any(SsaRead k)) and - ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read - * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a - * path between them without any read of `def`. - */ -pragma[nomagic] -predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and - bb2 = bb1 - ) - or - lastSsaRef(def, _, bb1, i1) and - defAdjacentRead(def, bb1, bb2, i2) -} - -pragma[noinline] -private predicate adjacentDefRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v -) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -private predicate adjacentDefReachesRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - ssaRef(bb1, i1, v, SsaDef()) - or - variableRead(bb1, i1, v, true) - ) - or - exists(BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `adjacentDefRead`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, true) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA definition - * `def`. The reference is last because it can reach another write `next`, - * without passing through another read or write. - */ -pragma[nomagic] -predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps - lastSsaRef(def, v, bb, i) and - exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and - 1 = ssaDefRank(next, v, bb2, _, SsaDef()) - ) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if `inp` is an immediately preceding definition of uncertain definition - * `def`. Since `def` is uncertain, the value from the preceding definition might - * still be valid. - */ -pragma[nomagic] -predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) -} - -private predicate adjacentDefReachesUncertainRead( - Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - variableRead(bb2, i2, _, false) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Holds if the node at index `i` in `bb` is a last reference to SSA - * definition `def`. - * - * That is, the node can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. - */ -pragma[nomagic] -predicate lastRef(Definition def, BasicBlock bb, int i) { - // Can reach another definition - lastRefRedef(def, bb, i, _) - or - exists(SourceVariable v | lastSsaRef(def, v, bb, i) | - // Can reach exit directly - bb instanceof ExitBasicBlock - or - // Can reach a block using one or more steps, where `def` is no longer live - varBlockReachesExit(def, bb) - ) -} - -/** - * NB: If this predicate is exposed, it should be cached. - * - * Same as `lastRefRedef`, but ignores uncertain reads. - */ -pragma[nomagic] -predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { - lastRef(def, bb, i) and - not variableRead(bb, i, def.getSourceVariable(), false) - or - exists(BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and - adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) - ) -} - -/** A static single assignment (SSA) definition. */ -class Definition extends TDefinition { - /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { this.definesAt(result, _, _) } - - /** - * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. - * Phi nodes are considered to be at index `-1`, while normal variable writes - * are at the index of the control flow node they wrap. - */ - final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { - this = TWriteDef(v, bb, i) - or - this = TPhiNode(v, bb) and i = -1 - } - - /** Gets the basic block to which this SSA definition belongs. */ - final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - - /** Gets a textual representation of this SSA definition. */ - string toString() { none() } -} - -/** An SSA definition that corresponds to a write. */ -class WriteDefinition extends Definition, TWriteDef { - private SourceVariable v; - private BasicBlock bb; - private int i; - - WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } -} - -/** A phi node. */ -class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } -} - -/** - * An SSA definition that represents an uncertain update of the underlying - * source variable. - */ -class UncertainWriteDefinition extends WriteDefinition { - UncertainWriteDefinition() { - exists(SourceVariable v, BasicBlock bb, int i | - this.definesAt(v, bb, i) and - variableWrite(bb, i, v, false) - ) - } -} - -/** Provides a set of consistency queries. */ -module Consistency { - abstract class RelevantDefinition extends Definition { - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); - } - - query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - ssaDefReachesRead(v, def, bb, i) and - not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) - } - - query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { - variableRead(bb, i, v, _) and - not ssaDefReachesRead(v, _, bb, i) - } - - query predicate deadDef(RelevantDefinition def, SourceVariable v) { - v = def.getSourceVariable() and - not ssaDefReachesRead(_, def, _, _) and - not phiHasInputFromBlock(_, def, _) and - not uncertainWriteDefinitionInput(_, def) - } - - query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { - exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | - ssaDefReachesReadWithinBlock(v, def, bb, i) and - (bb != bbDef or i < iDef) - or - ssaDefReachesRead(v, def, bb, i) and - not ssaDefReachesReadWithinBlock(v, def, bb, i) and - not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll deleted file mode 100644 index f095926e2a4..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll +++ /dev/null @@ -1,51 +0,0 @@ -/** Provides the C# specific parameters for `SsaImplCommon.qll`. */ - -private import csharp -private import AssignableDefinitions - -class BasicBlock = ControlFlow::BasicBlock; - -BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } - -BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - -class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock; - -pragma[noinline] -private Callable getAnAssigningCallable(LocalScopeVariable v) { - result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable() -} - -class SourceVariable extends LocalScopeVariable { - SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) } -} - -/** - * Holds if the `i`th node of basic block `bb` is assignable definition `def`, - * targeting local scope variable `v`. - */ -predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) { - bb.getNode(i) = def.getAControlFlowNode() and - v = def.getTarget() and - // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` - not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | - second.getAssignment() = first.getAssignment() and - second.getEvaluationOrder() > first.getEvaluationOrder() and - second.getTarget() = v - ) -} - -predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { - exists(AssignableDefinition def | - definitionAt(def, bb, i, v) and - if def.isCertain() then certain = true else certain = false - ) -} - -predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { - exists(AssignableRead read | - read.getAControlFlowNode() = bb.getNode(i) and - read.getTarget() = v and - certain = true - ) -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index e6ce1ada8d4..bf937b6de31 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration { } override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - (this.isSink(node) or this.isAdditionalTaintStep(node, _)) and + ( + this.isSink(node) or + this.isSink(node, _) or + this.isAdditionalTaintStep(node, _) or + this.isAdditionalTaintStep(node, _, _, _) + ) and defaultImplicitTaintRead(node, c) } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/GeneratedNegative.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/GeneratedNegative.qll index 0e1c66e251d..a7fb4c6c58c 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/GeneratedNegative.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/GeneratedNegative.qll @@ -1,9 +1,8 @@ +/** Provides a module for importing negative models. */ + /** * A module importing all generated negative Models as Data models. */ - -import csharp - private module GeneratedFrameworks { private import generated.dotnet.NegativeRuntime } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll index e878179d7f8..652ec19a86a 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll @@ -71,6 +71,8 @@ private class SystemArrayFlowModelCsv extends SummaryModelCsv { row = [ "System;Array;false;AsReadOnly<>;(T[]);;Argument[0].Element;ReturnValue.Element;value;manual", + "System;Array;false;Clear;(System.Array,System.Int32,System.Int32);;Argument[0].WithoutElement;Argument[0];value;manual", + "System;Array;false;Clear;(System.Array);;Argument[0].WithoutElement;Argument[0];value;manual", "System;Array;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual", "System;Array;false;CopyTo;(System.Array,System.Int64);;Argument[this].Element;Argument[0].Element;value;manual", "System;Array;false;Find<>;(T[],System.Predicate);;Argument[0].Element;Argument[1].Parameter[0];value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/NegativeRuntime.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/NegativeRuntime.qll index 8abcb5071c7..eaf039352de 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/NegativeRuntime.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/NegativeRuntime.qll @@ -3237,7 +3237,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.CodeDom.Compiler;IndentedTextWriter;Close;();generated", "System.CodeDom.Compiler;IndentedTextWriter;DisposeAsync;();generated", "System.CodeDom.Compiler;IndentedTextWriter;Flush;();generated", - "System.CodeDom.Compiler;IndentedTextWriter;FlushAsync;();generated", "System.CodeDom.Compiler;IndentedTextWriter;IndentedTextWriter;(System.IO.TextWriter);generated", "System.CodeDom.Compiler;IndentedTextWriter;OutputTabs;();generated", "System.CodeDom.Compiler;IndentedTextWriter;OutputTabsAsync;();generated", @@ -3281,7 +3280,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.String);generated", "System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);generated", "System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabs;(System.String);generated", - "System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabsAsync;(System.String);generated", "System.CodeDom.Compiler;IndentedTextWriter;get_Indent;();generated", "System.CodeDom.Compiler;IndentedTextWriter;set_Indent;(System.Int32);generated", "System.CodeDom.Compiler;TempFileCollection;AddFile;(System.String,System.Boolean);generated", @@ -3459,7 +3457,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.CodeDom;CodeNamespaceImport;set_LinePragma;(System.CodeDom.CodeLinePragma);generated", "System.CodeDom;CodeNamespaceImportCollection;Clear;();generated", "System.CodeDom;CodeNamespaceImportCollection;Contains;(System.Object);generated", - "System.CodeDom;CodeNamespaceImportCollection;GetEnumerator;();generated", "System.CodeDom;CodeNamespaceImportCollection;IndexOf;(System.Object);generated", "System.CodeDom;CodeNamespaceImportCollection;Remove;(System.Object);generated", "System.CodeDom;CodeNamespaceImportCollection;RemoveAt;(System.Int32);generated", @@ -3612,7 +3609,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair);generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Object);generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;ContainsKey;(TKey);generated", - "System.Collections.Concurrent;ConcurrentDictionary<,>;GetEnumerator;();generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Collections.Generic.KeyValuePair);generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Object);generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(TKey);generated", @@ -3676,9 +3672,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Generic;ByteEqualityComparer;Equals;(System.Object);generated", "System.Collections.Generic;ByteEqualityComparer;GetHashCode;();generated", "System.Collections.Generic;ByteEqualityComparer;GetHashCode;(System.Byte);generated", - "System.Collections.Generic;CollectionExtensions;AsReadOnly<,>;(System.Collections.Generic.IDictionary);generated", "System.Collections.Generic;CollectionExtensions;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey);generated", - "System.Collections.Generic;CollectionExtensions;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);generated", "System.Collections.Generic;Comparer<>;Compare;(System.Object,System.Object);generated", "System.Collections.Generic;Comparer<>;Compare;(T,T);generated", "System.Collections.Generic;Comparer<>;get_Default;();generated", @@ -3819,7 +3813,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", "System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String);generated", "System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String,System.Exception);generated", - "System.Collections.Generic;KeyValuePair;Create<,>;(TKey,TValue);generated", "System.Collections.Generic;KeyValuePair<,>;ToString;();generated", "System.Collections.Generic;LinkedList<>+Enumerator;Dispose;();generated", "System.Collections.Generic;LinkedList<>+Enumerator;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", @@ -4172,9 +4165,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;();generated", "System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer);generated", "System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);generated", - "System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable>);generated", - "System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated", - "System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated", "System.Collections.Immutable;ImmutableDictionary;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary,TKey);generated", "System.Collections.Immutable;ImmutableDictionary<,>+Builder;Clear;();generated", "System.Collections.Immutable;ImmutableDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair);generated", @@ -4264,10 +4254,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableInterlocked;TryRemove<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue);generated", "System.Collections.Immutable;ImmutableInterlocked;TryUpdate<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue,TValue);generated", "System.Collections.Immutable;ImmutableList;Create<>;();generated", - "System.Collections.Immutable;ImmutableList;Create<>;(T);generated", "System.Collections.Immutable;ImmutableList;Create<>;(T[]);generated", "System.Collections.Immutable;ImmutableList;CreateBuilder<>;();generated", - "System.Collections.Immutable;ImmutableList;CreateRange<>;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T);generated", "System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T,System.Collections.Generic.IEqualityComparer);generated", "System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T,System.Int32);generated", @@ -4331,9 +4319,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableQueue<>;get_IsEmpty;();generated", "System.Collections.Immutable;ImmutableSortedDictionary;Create<,>;();generated", "System.Collections.Immutable;ImmutableSortedDictionary;CreateBuilder<,>;();generated", - "System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);generated", - "System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated", - "System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable>);generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Clear;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair);generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Object);generated", @@ -4353,7 +4338,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Dispose;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;MoveNext;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Reset;();generated", - "System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;get_Current;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;Clear;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair);generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Object);generated", @@ -4370,8 +4354,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsReadOnly;();generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsSynchronized;();generated", "System.Collections.Immutable;ImmutableSortedSet;Create<>;();generated", - "System.Collections.Immutable;ImmutableSortedSet;Create<>;(System.Collections.Generic.IComparer,T);generated", - "System.Collections.Immutable;ImmutableSortedSet;Create<>;(T);generated", "System.Collections.Immutable;ImmutableSortedSet;Create<>;(T[]);generated", "System.Collections.Immutable;ImmutableSortedSet;CreateBuilder<>;();generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;Clear;();generated", @@ -4385,7 +4367,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableSortedSet<>+Builder;Overlaps;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;Remove;(T);generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;SetEquals;(System.Collections.Generic.IEnumerable);generated", - "System.Collections.Immutable;ImmutableSortedSet<>+Builder;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_Count;();generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsReadOnly;();generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsSynchronized;();generated", @@ -4399,7 +4380,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableSortedSet<>;ExceptWith;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(System.Object);generated", "System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(T);generated", - "System.Collections.Immutable;ImmutableSortedSet<>;Intersect;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;IntersectWith;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;IsProperSubsetOf;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;IsProperSupersetOf;(System.Collections.Generic.IEnumerable);generated", @@ -4411,7 +4391,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Collections.Immutable;ImmutableSortedSet<>;Remove;(T);generated", "System.Collections.Immutable;ImmutableSortedSet<>;RemoveAt;(System.Int32);generated", "System.Collections.Immutable;ImmutableSortedSet<>;SetEquals;(System.Collections.Generic.IEnumerable);generated", - "System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExcept;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;UnionWith;(System.Collections.Generic.IEnumerable);generated", "System.Collections.Immutable;ImmutableSortedSet<>;get_Count;();generated", @@ -4819,7 +4798,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.Collections.Generic.IEnumerable);generated", "System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog[]);generated", "System.ComponentModel.Composition.Hosting;AggregateCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;AggregateCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;AggregateExportProvider;AggregateExportProvider;(System.Collections.Generic.IEnumerable);generated", @@ -4827,13 +4805,11 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Hosting;AggregateExportProvider;Dispose;(System.Boolean);generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;ApplicationCatalog;();generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;ApplicationCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;ToString;();generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_DisplayName;();generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_Origin;();generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;AssemblyCatalog;(System.String);generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;AssemblyCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;get_Origin;();generated", "System.ComponentModel.Composition.Hosting;AtomicComposition;AtomicComposition;();generated", "System.ComponentModel.Composition.Hosting;AtomicComposition;Complete;();generated", @@ -4869,7 +4845,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Hosting;CompositionContainer;SatisfyImportsOnce;(System.ComponentModel.Composition.Primitives.ComposablePart);generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;CompositionScopeDefinition;();generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;CompositionService;Dispose;();generated", @@ -4879,7 +4854,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext);generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;DirectoryCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;Refresh;();generated", @@ -4902,7 +4876,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;get_AtomicComposition;();generated", "System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;set_AtomicComposition;(System.ComponentModel.Composition.Hosting.AtomicComposition);generated", "System.ComponentModel.Composition.Hosting;FilteredCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Hosting;FilteredCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependencies;();generated", "System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependents;();generated", "System.ComponentModel.Composition.Hosting;FilteredCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated", @@ -4936,7 +4909,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;ComposablePartCatalog;();generated", "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;();generated", "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;(System.Boolean);generated", - "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated", "System.ComponentModel.Composition.Primitives;ComposablePartDefinition;ComposablePartDefinition;();generated", "System.ComponentModel.Composition.Primitives;ComposablePartDefinition;CreatePart;();generated", "System.ComponentModel.Composition.Primitives;ComposablePartDefinition;get_ExportDefinitions;();generated", @@ -6364,7 +6336,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_ComponentType;();generated", "System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_IsReadOnly;();generated", "System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_PropertyType;();generated", - "System.ComponentModel;TypeConverter+StandardValuesCollection;GetEnumerator;();generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;get_Count;();generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;get_IsSynchronized;();generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;get_SyncRoot;();generated", @@ -7511,14 +7482,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data.Common;DbCommand;DbCommand;();generated", "System.Data.Common;DbCommand;DisposeAsync;();generated", "System.Data.Common;DbCommand;ExecuteDbDataReader;(System.Data.CommandBehavior);generated", - "System.Data.Common;DbCommand;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated", "System.Data.Common;DbCommand;ExecuteNonQuery;();generated", "System.Data.Common;DbCommand;ExecuteNonQueryAsync;();generated", "System.Data.Common;DbCommand;ExecuteNonQueryAsync;(System.Threading.CancellationToken);generated", - "System.Data.Common;DbCommand;ExecuteReaderAsync;();generated", - "System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior);generated", - "System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated", - "System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Threading.CancellationToken);generated", "System.Data.Common;DbCommand;ExecuteScalar;();generated", "System.Data.Common;DbCommand;ExecuteScalarAsync;();generated", "System.Data.Common;DbCommand;ExecuteScalarAsync;(System.Threading.CancellationToken);generated", @@ -7602,7 +7568,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data.Common;DbConnectionStringBuilder;GetDefaultEvent;();generated", "System.Data.Common;DbConnectionStringBuilder;GetDefaultProperty;();generated", "System.Data.Common;DbConnectionStringBuilder;GetEditor;(System.Type);generated", - "System.Data.Common;DbConnectionStringBuilder;GetEnumerator;();generated", "System.Data.Common;DbConnectionStringBuilder;GetEvents;();generated", "System.Data.Common;DbConnectionStringBuilder;GetEvents;(System.Attribute[]);generated", "System.Data.Common;DbConnectionStringBuilder;GetProperties;(System.Collections.Hashtable);generated", @@ -7670,8 +7635,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data.Common;DbDataReader;GetDecimal;(System.Int32);generated", "System.Data.Common;DbDataReader;GetDouble;(System.Int32);generated", "System.Data.Common;DbDataReader;GetFieldType;(System.Int32);generated", - "System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32);generated", - "System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);generated", "System.Data.Common;DbDataReader;GetFloat;(System.Int32);generated", "System.Data.Common;DbDataReader;GetGuid;(System.Int32);generated", "System.Data.Common;DbDataReader;GetInt16;(System.Int32);generated", @@ -7681,7 +7644,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data.Common;DbDataReader;GetOrdinal;(System.String);generated", "System.Data.Common;DbDataReader;GetProviderSpecificFieldType;(System.Int32);generated", "System.Data.Common;DbDataReader;GetSchemaTable;();generated", - "System.Data.Common;DbDataReader;GetSchemaTableAsync;(System.Threading.CancellationToken);generated", "System.Data.Common;DbDataReader;GetStream;(System.Int32);generated", "System.Data.Common;DbDataReader;GetString;(System.Int32);generated", "System.Data.Common;DbDataReader;GetValue;(System.Int32);generated", @@ -8993,9 +8955,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data;DataColumnChangeEventArgs;get_ProposedValue;();generated", "System.Data;DataColumnChangeEventArgs;get_Row;();generated", "System.Data;DataColumnChangeEventArgs;set_ProposedValue;(System.Object);generated", - "System.Data;DataColumnCollection;Add;();generated", - "System.Data;DataColumnCollection;Add;(System.String,System.Type);generated", - "System.Data;DataColumnCollection;Add;(System.String,System.Type,System.String);generated", "System.Data;DataColumnCollection;CanRemove;(System.Data.DataColumn);generated", "System.Data;DataColumnCollection;Clear;();generated", "System.Data;DataColumnCollection;Contains;(System.String);generated", @@ -9018,7 +8977,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data;DataReaderExtensions;GetDecimal;(System.Data.Common.DbDataReader,System.String);generated", "System.Data;DataReaderExtensions;GetDouble;(System.Data.Common.DbDataReader,System.String);generated", "System.Data;DataReaderExtensions;GetFieldType;(System.Data.Common.DbDataReader,System.String);generated", - "System.Data;DataReaderExtensions;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);generated", "System.Data;DataReaderExtensions;GetFloat;(System.Data.Common.DbDataReader,System.String);generated", "System.Data;DataReaderExtensions;GetInt16;(System.Data.Common.DbDataReader,System.String);generated", "System.Data;DataReaderExtensions;GetInt32;(System.Data.Common.DbDataReader,System.String);generated", @@ -9036,10 +8994,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data;DataRelation;get_Nested;();generated", "System.Data;DataRelation;get_ParentTable;();generated", "System.Data;DataRelation;set_Nested;(System.Boolean);generated", - "System.Data;DataRelationCollection;Add;(System.Data.DataColumn,System.Data.DataColumn);generated", - "System.Data;DataRelationCollection;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);generated", - "System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);generated", - "System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);generated", "System.Data;DataRelationCollection;AddCore;(System.Data.DataRelation);generated", "System.Data;DataRelationCollection;CanRemove;(System.Data.DataRelation);generated", "System.Data;DataRelationCollection;Clear;();generated", @@ -9286,7 +9240,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Data;DataTableClearEventArgs;get_Table;();generated", "System.Data;DataTableClearEventArgs;get_TableName;();generated", "System.Data;DataTableClearEventArgs;get_TableNamespace;();generated", - "System.Data;DataTableCollection;Add;();generated", "System.Data;DataTableCollection;CanRemove;(System.Data.DataTable);generated", "System.Data;DataTableCollection;Clear;();generated", "System.Data;DataTableCollection;Contains;(System.String);generated", @@ -13442,19 +13395,15 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Drawing.Printing;PrinterResolution;set_X;(System.Int32);generated", "System.Drawing.Printing;PrinterResolution;set_Y;(System.Int32);generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;CopyTo;(System.Drawing.Printing.PaperSize[],System.Int32);generated", - "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;GetEnumerator;();generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_Count;();generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_IsSynchronized;();generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;CopyTo;(System.Drawing.Printing.PaperSource[],System.Int32);generated", - "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;GetEnumerator;();generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_Count;();generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_IsSynchronized;();generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;CopyTo;(System.Drawing.Printing.PrinterResolution[],System.Int32);generated", - "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;GetEnumerator;();generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_Count;();generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_IsSynchronized;();generated", "System.Drawing.Printing;PrinterSettings+StringCollection;CopyTo;(System.String[],System.Int32);generated", - "System.Drawing.Printing;PrinterSettings+StringCollection;GetEnumerator;();generated", "System.Drawing.Printing;PrinterSettings+StringCollection;get_Count;();generated", "System.Drawing.Printing;PrinterSettings+StringCollection;get_IsSynchronized;();generated", "System.Drawing.Printing;PrinterSettings;Clone;();generated", @@ -15785,12 +15734,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO.Compression;DeflateStream;EndWrite;(System.IAsyncResult);generated", "System.IO.Compression;DeflateStream;Flush;();generated", "System.IO.Compression;DeflateStream;Read;(System.Span);generated", - "System.IO.Compression;DeflateStream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated", "System.IO.Compression;DeflateStream;ReadByte;();generated", "System.IO.Compression;DeflateStream;Seek;(System.Int64,System.IO.SeekOrigin);generated", "System.IO.Compression;DeflateStream;SetLength;(System.Int64);generated", "System.IO.Compression;DeflateStream;Write;(System.ReadOnlySpan);generated", - "System.IO.Compression;DeflateStream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated", "System.IO.Compression;DeflateStream;WriteByte;(System.Byte);generated", "System.IO.Compression;DeflateStream;get_CanRead;();generated", "System.IO.Compression;DeflateStream;get_CanSeek;();generated", @@ -15806,12 +15753,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel);generated", "System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode);generated", "System.IO.Compression;GZipStream;Read;(System.Span);generated", - "System.IO.Compression;GZipStream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated", "System.IO.Compression;GZipStream;ReadByte;();generated", "System.IO.Compression;GZipStream;Seek;(System.Int64,System.IO.SeekOrigin);generated", "System.IO.Compression;GZipStream;SetLength;(System.Int64);generated", "System.IO.Compression;GZipStream;Write;(System.ReadOnlySpan);generated", - "System.IO.Compression;GZipStream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated", "System.IO.Compression;GZipStream;WriteByte;(System.Byte);generated", "System.IO.Compression;GZipStream;get_CanRead;();generated", "System.IO.Compression;GZipStream;get_CanSeek;();generated", @@ -16383,7 +16328,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;BinaryWriter;BinaryWriter;(System.IO.Stream,System.Text.Encoding);generated", "System.IO;BinaryWriter;Close;();generated", "System.IO;BinaryWriter;Dispose;();generated", "System.IO;BinaryWriter;Dispose;(System.Boolean);generated", - "System.IO;BinaryWriter;DisposeAsync;();generated", "System.IO;BinaryWriter;Flush;();generated", "System.IO;BinaryWriter;Seek;(System.Int32,System.IO.SeekOrigin);generated", "System.IO;BinaryWriter;Write7BitEncodedInt64;(System.Int64);generated", @@ -16774,18 +16718,14 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;Stream;DisposeAsync;();generated", "System.IO;Stream;EndRead;(System.IAsyncResult);generated", "System.IO;Stream;EndWrite;(System.IAsyncResult);generated", - "System.IO;Stream;Flush;();generated", "System.IO;Stream;FlushAsync;();generated", - "System.IO;Stream;FlushAsync;(System.Threading.CancellationToken);generated", - "System.IO;Stream;ObjectInvariant;();generated", + "System.IO;Stream;Flush;();generated", "System.IO;Stream;ObjectInvariant;();generated", "System.IO;Stream;Read;(System.Span);generated", - "System.IO;Stream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated", "System.IO;Stream;ReadByte;();generated", "System.IO;Stream;Seek;(System.Int64,System.IO.SeekOrigin);generated", "System.IO;Stream;SetLength;(System.Int64);generated", "System.IO;Stream;ValidateBufferArguments;(System.Byte[],System.Int32,System.Int32);generated", "System.IO;Stream;ValidateCopyToArguments;(System.IO.Stream,System.Int32);generated", "System.IO;Stream;Write;(System.ReadOnlySpan);generated", - "System.IO;Stream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated", "System.IO;Stream;WriteByte;(System.Byte);generated", "System.IO;Stream;get_CanRead;();generated", "System.IO;Stream;get_CanSeek;();generated", "System.IO;Stream;get_CanTimeout;();generated", @@ -16805,7 +16745,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;StreamWriter;Dispose;(System.Boolean);generated", "System.IO;StreamWriter;DisposeAsync;();generated", "System.IO;StreamWriter;Flush;();generated", - "System.IO;StreamWriter;FlushAsync;();generated", "System.IO;StreamWriter;StreamWriter;(System.IO.Stream);generated", "System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding);generated", "System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32);generated", @@ -16824,15 +16763,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;StreamWriter;Write;(System.String,System.Object,System.Object);generated", "System.IO;StreamWriter;Write;(System.String,System.Object,System.Object,System.Object);generated", "System.IO;StreamWriter;Write;(System.String,System.Object[]);generated", - "System.IO;StreamWriter;WriteAsync;(System.Char);generated", - "System.IO;StreamWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated", - "System.IO;StreamWriter;WriteAsync;(System.String);generated", "System.IO;StreamWriter;WriteLine;(System.ReadOnlySpan);generated", "System.IO;StreamWriter;WriteLine;(System.String);generated", - "System.IO;StreamWriter;WriteLineAsync;();generated", - "System.IO;StreamWriter;WriteLineAsync;(System.Char);generated", - "System.IO;StreamWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated", - "System.IO;StreamWriter;WriteLineAsync;(System.String);generated", "System.IO;StreamWriter;get_AutoFlush;();generated", "System.IO;StreamWriter;set_AutoFlush;(System.Boolean);generated", "System.IO;StringReader;Close;();generated", @@ -16845,10 +16777,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;StringWriter;StringWriter;(System.Text.StringBuilder);generated", "System.IO;StringWriter;Write;(System.Char);generated", "System.IO;StringWriter;Write;(System.ReadOnlySpan);generated", - "System.IO;StringWriter;Write;(System.Text.StringBuilder);generated", "System.IO;StringWriter;WriteAsync;(System.Char);generated", "System.IO;StringWriter;WriteLine;(System.ReadOnlySpan);generated", - "System.IO;StringWriter;WriteLine;(System.Text.StringBuilder);generated", "System.IO;StringWriter;WriteLineAsync;(System.Char);generated", "System.IO;StringWriter;get_Encoding;();generated", "System.IO;TextReader;Close;();generated", "System.IO;TextReader;Dispose;();generated", @@ -16857,7 +16787,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;TextWriter;Close;();generated", "System.IO;TextWriter;Dispose;();generated", "System.IO;TextWriter;Dispose;(System.Boolean);generated", "System.IO;TextWriter;DisposeAsync;();generated", "System.IO;TextWriter;Flush;();generated", - "System.IO;TextWriter;FlushAsync;();generated", "System.IO;TextWriter;TextWriter;();generated", "System.IO;TextWriter;Write;(System.Boolean);generated", "System.IO;TextWriter;Write;(System.Char);generated", @@ -16872,9 +16801,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;TextWriter;Write;(System.Text.StringBuilder);generated", "System.IO;TextWriter;Write;(System.UInt32);generated", "System.IO;TextWriter;Write;(System.UInt64);generated", - "System.IO;TextWriter;WriteAsync;(System.Char);generated", - "System.IO;TextWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated", - "System.IO;TextWriter;WriteAsync;(System.String);generated", "System.IO;TextWriter;WriteLine;();generated", "System.IO;TextWriter;WriteLine;(System.Boolean);generated", "System.IO;TextWriter;WriteLine;(System.Char);generated", @@ -16884,13 +16810,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.IO;TextWriter;WriteLine;(System.Int64);generated", "System.IO;TextWriter;WriteLine;(System.ReadOnlySpan);generated", "System.IO;TextWriter;WriteLine;(System.Single);generated", - "System.IO;TextWriter;WriteLine;(System.Text.StringBuilder);generated", "System.IO;TextWriter;WriteLine;(System.UInt32);generated", "System.IO;TextWriter;WriteLine;(System.UInt64);generated", - "System.IO;TextWriter;WriteLineAsync;();generated", - "System.IO;TextWriter;WriteLineAsync;(System.Char);generated", - "System.IO;TextWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated", - "System.IO;TextWriter;WriteLineAsync;(System.String);generated", "System.IO;TextWriter;get_Encoding;();generated", "System.IO;UnmanagedMemoryAccessor;Dispose;();generated", "System.IO;UnmanagedMemoryAccessor;Dispose;(System.Boolean);generated", @@ -18094,7 +18015,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;Reset;();generated", "System.Net.Http.Headers;HttpHeadersNonValidated;Contains;(System.String);generated", "System.Net.Http.Headers;HttpHeadersNonValidated;ContainsKey;(System.String);generated", - "System.Net.Http.Headers;HttpHeadersNonValidated;GetEnumerator;();generated", "System.Net.Http.Headers;HttpHeadersNonValidated;get_Count;();generated", "System.Net.Http.Headers;HttpRequestHeaders;get_Accept;();generated", "System.Net.Http.Headers;HttpRequestHeaders;get_AcceptCharset;();generated", @@ -18283,7 +18203,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Http.Json;JsonContent;TryComputeLength;(System.Int64);generated", "System.Net.Http.Json;JsonContent;get_ObjectType;();generated", "System.Net.Http.Json;JsonContent;get_Value;();generated", - "System.Net.Http;ByteArrayContent;CreateContentReadStreamAsync;();generated", "System.Net.Http;ByteArrayContent;TryComputeLength;(System.Int64);generated", "System.Net.Http;DelegatingHandler;DelegatingHandler;();generated", "System.Net.Http;DelegatingHandler;Dispose;(System.Boolean);generated", @@ -18383,7 +18302,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Http;HttpClientHandler;set_UseDefaultCredentials;(System.Boolean);generated", "System.Net.Http;HttpClientHandler;set_UseProxy;(System.Boolean);generated", "System.Net.Http;HttpContent;CreateContentReadStreamAsync;();generated", - "System.Net.Http;HttpContent;CreateContentReadStreamAsync;(System.Threading.CancellationToken);generated", "System.Net.Http;HttpContent;Dispose;();generated", "System.Net.Http;HttpContent;Dispose;(System.Boolean);generated", "System.Net.Http;HttpContent;HttpContent;();generated", @@ -18472,7 +18390,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Http;MultipartContent;get_HeaderEncodingSelector;();generated", "System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;();generated", "System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;(System.String);generated", - "System.Net.Http;ReadOnlyMemoryContent;CreateContentReadStreamAsync;();generated", "System.Net.Http;ReadOnlyMemoryContent;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated", "System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);generated", "System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated", @@ -19103,7 +19020,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Quic;QuicStreamAbortedException;QuicStreamAbortedException;(System.String,System.Int64);generated", "System.Net.Quic;QuicStreamAbortedException;get_ErrorCode;();generated", "System.Net.Security;AuthenticatedStream;Dispose;(System.Boolean);generated", - "System.Net.Security;AuthenticatedStream;DisposeAsync;();generated", "System.Net.Security;AuthenticatedStream;get_IsAuthenticated;();generated", "System.Net.Security;AuthenticatedStream;get_IsEncrypted;();generated", "System.Net.Security;AuthenticatedStream;get_IsMutuallyAuthenticated;();generated", @@ -19328,7 +19244,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Sockets;SendPacketsElement;set_MemoryBuffer;(System.Nullable>);generated", "System.Net.Sockets;SendPacketsElement;set_OffsetLong;(System.Int64);generated", "System.Net.Sockets;Socket;AcceptAsync;();generated", - "System.Net.Sockets;Socket;AcceptAsync;(System.Net.Sockets.Socket);generated", "System.Net.Sockets;Socket;CancelConnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);generated", "System.Net.Sockets;Socket;Close;();generated", "System.Net.Sockets;Socket;Close;(System.Int32);generated", @@ -19343,7 +19258,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Sockets;Socket;DuplicateAndClose;(System.Int32);generated", "System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.IAsyncResult);generated", "System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.Int32,System.IAsyncResult);generated", - "System.Net.Sockets;Socket;EndAccept;(System.IAsyncResult);generated", "System.Net.Sockets;Socket;EndConnect;(System.IAsyncResult);generated", "System.Net.Sockets;Socket;EndDisconnect;(System.IAsyncResult);generated", "System.Net.Sockets;Socket;EndReceive;(System.IAsyncResult);generated", @@ -19378,10 +19292,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Sockets;Socket;ReceiveAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags);generated", "System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList>);generated", "System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated", - "System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment,System.Net.EndPoint);generated", - "System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated", - "System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.EndPoint);generated", - "System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated", "System.Net.Sockets;Socket;Select;(System.Collections.IList,System.Collections.IList,System.Collections.IList,System.Int32);generated", "System.Net.Sockets;Socket;Send;(System.Byte[]);generated", "System.Net.Sockets;Socket;Send;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags);generated", @@ -19481,14 +19391,11 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Sockets;SocketInformation;set_Options;(System.Net.Sockets.SocketInformationOptions);generated", "System.Net.Sockets;SocketInformation;set_ProtocolInformation;(System.Byte[]);generated", "System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket);generated", - "System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);generated", "System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32);generated", "System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32,System.Threading.CancellationToken);generated", "System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.String,System.Int32);generated", "System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags);generated", "System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated", - "System.Net.Sockets;SocketTaskExtensions;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated", - "System.Net.Sockets;SocketTaskExtensions;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated", "System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags);generated", "System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated", "System.Net.Sockets;TcpClient;Close;();generated", @@ -19530,8 +19437,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net.Sockets;TcpListener;AcceptTcpClientAsync;(System.Threading.CancellationToken);generated", "System.Net.Sockets;TcpListener;AllowNatTraversal;(System.Boolean);generated", "System.Net.Sockets;TcpListener;Create;(System.Int32);generated", - "System.Net.Sockets;TcpListener;EndAcceptSocket;(System.IAsyncResult);generated", - "System.Net.Sockets;TcpListener;EndAcceptTcpClient;(System.IAsyncResult);generated", "System.Net.Sockets;TcpListener;Pending;();generated", "System.Net.Sockets;TcpListener;Start;();generated", "System.Net.Sockets;TcpListener;Start;(System.Int32);generated", @@ -19748,10 +19653,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net;CredentialCache;Remove;(System.Uri,System.String);generated", "System.Net;CredentialCache;get_DefaultCredentials;();generated", "System.Net;CredentialCache;get_DefaultNetworkCredentials;();generated", - "System.Net;Dns;EndGetHostAddresses;(System.IAsyncResult);generated", - "System.Net;Dns;EndGetHostByName;(System.IAsyncResult);generated", - "System.Net;Dns;EndGetHostEntry;(System.IAsyncResult);generated", - "System.Net;Dns;EndResolve;(System.IAsyncResult);generated", "System.Net;Dns;GetHostAddresses;(System.String);generated", "System.Net;Dns;GetHostAddresses;(System.String,System.Net.Sockets.AddressFamily);generated", "System.Net;Dns;GetHostAddressesAsync;(System.String);generated", @@ -19795,8 +19696,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net;EndpointPermission;get_Port;();generated", "System.Net;EndpointPermission;get_Transport;();generated", "System.Net;FileWebRequest;Abort;();generated", - "System.Net;FileWebRequest;EndGetRequestStream;(System.IAsyncResult);generated", - "System.Net;FileWebRequest;EndGetResponse;(System.IAsyncResult);generated", "System.Net;FileWebRequest;FileWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", "System.Net;FileWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", "System.Net;FileWebRequest;GetRequestStreamAsync;();generated", @@ -19951,9 +19850,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net;HttpWebRequest;AddRange;(System.String,System.Int32,System.Int32);generated", "System.Net;HttpWebRequest;AddRange;(System.String,System.Int64);generated", "System.Net;HttpWebRequest;AddRange;(System.String,System.Int64,System.Int64);generated", - "System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult);generated", - "System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);generated", - "System.Net;HttpWebRequest;EndGetResponse;(System.IAsyncResult);generated", "System.Net;HttpWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", "System.Net;HttpWebRequest;HttpWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", "System.Net;HttpWebRequest;get_AllowAutoRedirect;();generated", @@ -20102,7 +19998,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Net;NetworkCredential;get_SecurePassword;();generated", "System.Net;NetworkCredential;set_SecurePassword;(System.Security.SecureString);generated", "System.Net;PathList;GetCookiesCount;();generated", - "System.Net;PathList;get_Count;();generated", "System.Net;PathList;get_Values;();generated", + "System.Net;PathList;get_Count;();generated", "System.Net;PathList;set_Item;(System.String,System.Object);generated", "System.Net;ProtocolViolationException;ProtocolViolationException;();generated", "System.Net;ProtocolViolationException;ProtocolViolationException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated", @@ -20488,6 +20384,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Numerics;BigInteger;Log;(System.Numerics.BigInteger,System.Double);generated", "System.Numerics;BigInteger;ModPow;(System.Numerics.BigInteger,System.Numerics.BigInteger,System.Numerics.BigInteger);generated", "System.Numerics;BigInteger;Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated", + "System.Numerics;BigInteger;Negate;(System.Numerics.BigInteger);generated", "System.Numerics;BigInteger;Parse;(System.ReadOnlySpan,System.Globalization.NumberStyles,System.IFormatProvider);generated", "System.Numerics;BigInteger;Parse;(System.String);generated", "System.Numerics;BigInteger;Parse;(System.String,System.Globalization.NumberStyles);generated", @@ -20553,6 +20450,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Numerics;BigInteger;op_Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated", "System.Numerics;BigInteger;op_OnesComplement;(System.Numerics.BigInteger);generated", "System.Numerics;BigInteger;op_Subtraction;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated", + "System.Numerics;BigInteger;op_UnaryNegation;(System.Numerics.BigInteger);generated", "System.Numerics;BitOperations;IsPow2;(System.Int32);generated", "System.Numerics;BitOperations;IsPow2;(System.Int64);generated", "System.Numerics;BitOperations;IsPow2;(System.IntPtr);generated", @@ -23476,7 +23374,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Resources;ResourceSet;Dispose;(System.Boolean);generated", "System.Resources;ResourceSet;GetDefaultReader;();generated", "System.Resources;ResourceSet;GetDefaultWriter;();generated", - "System.Resources;ResourceSet;GetEnumerator;();generated", "System.Resources;ResourceSet;GetObject;(System.String);generated", "System.Resources;ResourceSet;GetObject;(System.String,System.Boolean);generated", "System.Resources;ResourceSet;GetString;(System.String);generated", @@ -23691,6 +23588,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Runtime.CompilerServices;DisablePrivateReflectionAttribute;DisablePrivateReflectionAttribute;();generated", "System.Runtime.CompilerServices;DiscardableAttribute;DiscardableAttribute;();generated", "System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;();generated", + "System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;(System.Boolean[]);generated", + "System.Runtime.CompilerServices;DynamicAttribute;get_TransformFlags;();generated", "System.Runtime.CompilerServices;EnumeratorCancellationAttribute;EnumeratorCancellationAttribute;();generated", "System.Runtime.CompilerServices;FixedAddressValueTypeAttribute;FixedAddressValueTypeAttribute;();generated", "System.Runtime.CompilerServices;FixedBufferAttribute;FixedBufferAttribute;(System.Type,System.Int32);generated", @@ -29676,7 +29575,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan);generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan);generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.String);generated", - "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;GetBags;();generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Pkcs12SafeContents;();generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_ConfidentialityMode;();generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_IsReadOnly;();generated", @@ -29984,7 +29882,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Security.Cryptography.X509Certificates;X509Certificate;get_Handle;();generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;MoveNext;();generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;Reset;();generated", - "System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection;Contains;(System.Security.Cryptography.X509Certificates.X509Certificate);generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection;GetHashCode;();generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection;IndexOf;(System.Security.Cryptography.X509Certificates.X509Certificate);generated", @@ -30154,7 +30051,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsReadOnly;();generated", "System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsSynchronized;();generated", "System.Security.Cryptography.Xml;IRelDecryptor;Decrypt;(System.Security.Cryptography.Xml.EncryptionMethod,System.Security.Cryptography.Xml.KeyInfo,System.IO.Stream);generated", - "System.Security.Cryptography.Xml;KeyInfo;GetEnumerator;(System.Type);generated", "System.Security.Cryptography.Xml;KeyInfo;GetXml;();generated", "System.Security.Cryptography.Xml;KeyInfo;KeyInfo;();generated", "System.Security.Cryptography.Xml;KeyInfo;get_Count;();generated", @@ -30221,7 +30117,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Security.Cryptography.Xml;Transform;Transform;();generated", "System.Security.Cryptography.Xml;Transform;get_InputTypes;();generated", "System.Security.Cryptography.Xml;Transform;get_OutputTypes;();generated", - "System.Security.Cryptography.Xml;TransformChain;GetEnumerator;();generated", "System.Security.Cryptography.Xml;TransformChain;TransformChain;();generated", "System.Security.Cryptography.Xml;TransformChain;get_Count;();generated", "System.Security.Cryptography.Xml;X509IssuerSerial;get_IssuerName;();generated", @@ -34394,7 +34289,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Text.Json.Serialization;ReferenceResolver;GetReference;(System.Object,System.Boolean);generated", "System.Text.Json.Serialization;ReferenceResolver;ResolveReference;(System.String);generated", "System.Text.Json.SourceGeneration;JsonSourceGenerator;Execute;(Microsoft.CodeAnalysis.GeneratorExecutionContext);generated", - "System.Text.Json.SourceGeneration;JsonSourceGenerator;GetSerializableTypes;();generated", "System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.GeneratorInitializationContext);generated", "System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext);generated", "System.Text.Json;JsonDocument;Dispose;();generated", @@ -35424,7 +35318,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Threading.RateLimiting;MetadataName<>;op_Inequality;(System.Threading.RateLimiting.MetadataName<>,System.Threading.RateLimiting.MetadataName<>);generated", "System.Threading.RateLimiting;RateLimitLease;Dispose;();generated", "System.Threading.RateLimiting;RateLimitLease;Dispose;(System.Boolean);generated", - "System.Threading.RateLimiting;RateLimitLease;GetAllMetadata;();generated", "System.Threading.RateLimiting;RateLimitLease;TryGetMetadata;(System.String,System.Object);generated", "System.Threading.RateLimiting;RateLimitLease;get_IsAcquired;();generated", "System.Threading.RateLimiting;RateLimitLease;get_MetadataNames;();generated", @@ -35507,10 +35400,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);generated", "System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);generated", "System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAllAsync<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock,System.Threading.CancellationToken);generated", - "System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);generated", - "System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);generated", - "System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);generated", - "System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);generated", "System.Threading.Tasks.Dataflow;DataflowBlock;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock,TInput);generated", "System.Threading.Tasks.Dataflow;DataflowBlockOptions;DataflowBlockOptions;();generated", "System.Threading.Tasks.Dataflow;DataflowBlockOptions;get_BoundedCapacity;();generated", @@ -36723,13 +36612,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Xml.Schema;XmlSchemaParticle;set_MinOccursString;(System.String);generated", "System.Xml.Schema;XmlSchemaPatternFacet;XmlSchemaPatternFacet;();generated", "System.Xml.Schema;XmlSchemaRedefine;XmlSchemaRedefine;();generated", - "System.Xml.Schema;XmlSchemaSet;Add;(System.Xml.Schema.XmlSchemaSet);generated", "System.Xml.Schema;XmlSchemaSet;Compile;();generated", "System.Xml.Schema;XmlSchemaSet;Contains;(System.String);generated", "System.Xml.Schema;XmlSchemaSet;Contains;(System.Xml.Schema.XmlSchema);generated", - "System.Xml.Schema;XmlSchemaSet;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);generated", "System.Xml.Schema;XmlSchemaSet;RemoveRecursive;(System.Xml.Schema.XmlSchema);generated", - "System.Xml.Schema;XmlSchemaSet;Schemas;();generated", "System.Xml.Schema;XmlSchemaSet;Schemas;(System.String);generated", "System.Xml.Schema;XmlSchemaSet;XmlSchemaSet;();generated", "System.Xml.Schema;XmlSchemaSet;get_Count;();generated", @@ -36982,7 +36868,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Xml.Serialization;XmlSerializationWriter;WriteEmptyTag;(System.String,System.String);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;();generated", "System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;(System.Object);generated", - "System.Xml.Serialization;XmlSerializationWriter;WriteId;(System.Object);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteNamespaceDeclarations;(System.Xml.Serialization.XmlSerializerNamespaces);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String,System.String);generated", @@ -36991,8 +36876,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameEncoded;(System.String,System.String,System.Xml.XmlQualifiedName,System.Xml.XmlQualifiedName);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameLiteral;(System.String,System.String,System.Xml.XmlQualifiedName);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteReferencedElements;();generated", - "System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object);generated", - "System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteStartDocument;();generated", "System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String);generated", "System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String,System.String);generated", @@ -41163,29 +41046,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv { "System;Tuple<>;Equals;(System.Object,System.Collections.IEqualityComparer);generated", "System;Tuple<>;GetHashCode;();generated", "System;Tuple<>;GetHashCode;(System.Collections.IEqualityComparer);generated", - "System;Tuple<>;get_Length;();generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,,>;(System.ValueTuple>);generated", - "System;TupleExtensions;ToTuple<,,,,,,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<,,,,,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<,,,,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<,,,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<,,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<,>;(System.ValueTuple);generated", - "System;TupleExtensions;ToTuple<>;(System.ValueTuple);generated", - "System;Type;Equals;(System.Object);generated", + "System;Tuple<>;get_Length;();generated", "System;Type;Equals;(System.Object);generated", "System;Type;Equals;(System.Type);generated", "System;Type;GetArrayRank;();generated", "System;Type;GetAttributeFlagsImpl;();generated", "System;Type;GetConstructorImpl;(System.Reflection.BindingFlags,System.Reflection.Binder,System.Reflection.CallingConventions,System.Type[],System.Reflection.ParameterModifier[]);generated", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/Runtime.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/Runtime.qll index b94322f77a7..65fa78671d7 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/Runtime.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/generated/dotnet/Runtime.qll @@ -13,7 +13,29 @@ private class RuntimeSinksCsv extends SinkModelCsv { "System.Data.Odbc;OdbcDataAdapter;false;OdbcDataAdapter;(System.String,System.Data.Odbc.OdbcConnection);;Argument[0];sql;generated", "System.Data.Odbc;OdbcDataAdapter;false;OdbcDataAdapter;(System.String,System.String);;Argument[0];sql;generated", "System.Net.Http;StringContent;false;StringContent;(System.String);;Argument[0];xss;generated", - "System.Net.Http;StringContent;false;StringContent;(System.String,System.Text.Encoding);;Argument[0];xss;generated" + "System.Net.Http;StringContent;false;StringContent;(System.String,System.Text.Encoding);;Argument[0];xss;generated", + "System.Security.Cryptography;AesCryptoServiceProvider;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;AesCryptoServiceProvider;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;AesCryptoServiceProvider;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;AesManaged;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;AesManaged;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;AesManaged;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;DES;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;DESCryptoServiceProvider;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;DESCryptoServiceProvider;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;DESCryptoServiceProvider;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;RC2CryptoServiceProvider;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;RC2CryptoServiceProvider;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;RC2CryptoServiceProvider;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;RijndaelManaged;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;RijndaelManaged;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;RijndaelManaged;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;SymmetricAlgorithm;true;CreateDecryptor;();;Argument[this];encryption-decryptor;generated", + "System.Security.Cryptography;SymmetricAlgorithm;true;CreateEncryptor;();;Argument[this];encryption-encryptor;generated", + "System.Security.Cryptography;TripleDES;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated", + "System.Security.Cryptography;TripleDESCryptoServiceProvider;false;CreateDecryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-decryptor;generated", + "System.Security.Cryptography;TripleDESCryptoServiceProvider;false;CreateEncryptor;(System.Byte[],System.Byte[]);;Argument[0];encryption-encryptor;generated", + "System.Security.Cryptography;TripleDESCryptoServiceProvider;false;set_Key;(System.Byte[]);;Argument[0];encryption-keyprop;generated" ] } } @@ -275,6 +297,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "Microsoft.Extensions.FileProviders.Composite;CompositeDirectoryContents;false;CompositeDirectoryContents;(System.Collections.Generic.IList,System.String);;Argument[1];Argument[this];taint;generated", "Microsoft.Extensions.FileProviders.Internal;PhysicalDirectoryContents;false;PhysicalDirectoryContents;(System.String,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated", "Microsoft.Extensions.FileProviders.Physical;PhysicalDirectoryInfo;false;PhysicalDirectoryInfo;(System.IO.DirectoryInfo);;Argument[0];Argument[this];taint;generated", + "Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;CreateReadStream;();;Argument[this];ReturnValue;taint;generated", "Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;PhysicalFileInfo;(System.IO.FileInfo);;Argument[0];Argument[this];taint;generated", "Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;get_PhysicalPath;();;Argument[this];ReturnValue;taint;generated", "Microsoft.Extensions.FileProviders.Physical;PhysicalFilesWatcher;false;PhysicalFilesWatcher;(System.String,System.IO.FileSystemWatcher,System.Boolean,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated", @@ -541,8 +564,11 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.CodeDom.Compiler;GeneratedCodeAttribute;false;GeneratedCodeAttribute;(System.String,System.String);;Argument[1];Argument[this];taint;generated", "System.CodeDom.Compiler;GeneratedCodeAttribute;false;get_Tool;();;Argument[this];ReturnValue;taint;generated", "System.CodeDom.Compiler;GeneratedCodeAttribute;false;get_Version;();;Argument[this];ReturnValue;taint;generated", + "System.CodeDom.Compiler;IndentedTextWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated", "System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[0];Argument[this];taint;generated", "System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[1];Argument[this];taint;generated", + "System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[this];ReturnValue;taint;generated", "System.CodeDom.Compiler;IndentedTextWriter;false;get_Encoding;();;Argument[this];ReturnValue;taint;generated", "System.CodeDom.Compiler;IndentedTextWriter;false;get_InnerWriter;();;Argument[this];ReturnValue;taint;generated", "System.CodeDom.Compiler;IndentedTextWriter;false;get_NewLine;();;Argument[this];ReturnValue;taint;generated", @@ -755,6 +781,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.CodeDom;CodeNamespaceImport;false;set_Namespace;(System.String);;Argument[0];Argument[this];taint;generated", "System.CodeDom;CodeNamespaceImportCollection;false;Add;(System.CodeDom.CodeNamespaceImport);;Argument[0];Argument[this];taint;generated", "System.CodeDom;CodeNamespaceImportCollection;false;AddRange;(System.CodeDom.CodeNamespaceImport[]);;Argument[0].Element;Argument[this];taint;generated", + "System.CodeDom;CodeNamespaceImportCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.CodeDom;CodeNamespaceImportCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.CodeDom;CodeNamespaceImportCollection;false;set_Item;(System.Int32,System.CodeDom.CodeNamespaceImport);;Argument[1];Argument[this];taint;generated", "System.CodeDom;CodeObject;false;get_UserData;();;Argument[this];ReturnValue;taint;generated", @@ -927,6 +954,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Concurrent;ConcurrentBag<>;false;TryAdd;(T);;Argument[0];Argument[this];taint;generated", "System.Collections.Concurrent;ConcurrentBag<>;false;TryPeek;(T);;Argument[this];ReturnValue;taint;generated", "System.Collections.Concurrent;ConcurrentBag<>;false;TryTake;(T);;Argument[this];ReturnValue;taint;generated", + "System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetOrAdd;(TKey,TValue);;Argument[1];ReturnValue;taint;generated", "System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Concurrent;ConcurrentStack<>;false;ConcurrentStack;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", @@ -940,6 +968,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Concurrent;Partitioner;false;Create<>;(System.Collections.Generic.IEnumerable,System.Collections.Concurrent.EnumerablePartitionerOptions);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Concurrent;Partitioner;false;Create<>;(System.Collections.Generic.IList,System.Boolean);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Concurrent;Partitioner;false;Create<>;(TSource[],System.Boolean);;Argument[0].Element;ReturnValue;taint;generated", + "System.Collections.Generic;CollectionExtensions;false;AsReadOnly<,>;(System.Collections.Generic.IDictionary);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Generic;CollectionExtensions;false;AsReadOnly<>;(System.Collections.Generic.IList);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Generic;CollectionExtensions;false;GetDefaultAssets;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Generic;CollectionExtensions;false;GetDefaultGroup;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated", @@ -951,6 +980,9 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[1];ReturnValue;taint;generated", "System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated", "System.Collections.Generic;CollectionExtensions;false;Remove<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;ReturnValue;taint;generated", + "System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;Argument[2];taint;generated", + "System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[1];Argument[0].Element;taint;generated", + "System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[2];Argument[0].Element;taint;generated", "System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Entry;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Key;();;Argument[this];ReturnValue;taint;generated", @@ -970,6 +1002,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Generic;HashSet<>;false;HashSet;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", "System.Collections.Generic;HashSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated", "System.Collections.Generic;HashSet<>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated", + "System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[1];ReturnValue;taint;generated", "System.Collections.Generic;KeyValuePair<,>;false;Deconstruct;(TKey,TValue);;Argument[this];ReturnValue;taint;generated", "System.Collections.Generic;KeyValuePair<,>;false;get_Key;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Generic;KeyValuePair<,>;false;get_Value;();;Argument[this];ReturnValue;taint;generated", @@ -1121,6 +1155,12 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary;false;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[0].Element;ReturnValue;taint;generated", @@ -1137,6 +1177,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;get_ValueComparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;set_KeyComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", "System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;set_ValueComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", + "System.Collections.Immutable;ImmutableDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary<,>;false;Remove;(TKey);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary<,>;false;RemoveRange;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableDictionary<,>;false;SetItem;(TKey,TValue);;Argument[this];ReturnValue;taint;generated", @@ -1158,6 +1199,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableHashSet<>+Builder;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>+Builder;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>+Builder;false;set_KeyComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", + "System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>;false;Intersect;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>;false;Remove;(T);;Argument[this];ReturnValue;taint;generated", @@ -1170,6 +1212,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableHashSet<>;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableHashSet<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Collections.Immutable;ImmutableInterlocked;false;GetOrAdd<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableList;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableList;false;CreateRange<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableList;false;Remove<>;(System.Collections.Immutable.IImmutableList,T);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableList;false;RemoveRange<>;(System.Collections.Immutable.IImmutableList,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableList;false;Replace<>;(System.Collections.Immutable.IImmutableList,T,T);;Argument[0].Element;ReturnValue;taint;generated", @@ -1228,6 +1272,12 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[1];ReturnValue;taint;generated", @@ -1244,6 +1294,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;get_ValueComparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_KeyComparer;(System.Collections.Generic.IComparer);;Argument[0];Argument[this];taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_ValueComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Remove;(TKey);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;RemoveRange;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;SetItem;(TKey,TValue);;Argument[0];ReturnValue;taint;generated", @@ -1261,7 +1313,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Collections.Immutable;ImmutableSortedDictionary<,>;false;get_ValueComparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[1];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T[]);;Argument[0];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;CreateBuilder<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue;taint;generated", @@ -1271,6 +1326,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableSortedSet;false;ToImmutableSortedSet<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IComparer);;Argument[1];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet;false;ToImmutableSortedSet<>;(System.Collections.Immutable.ImmutableSortedSet+Builder);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;IntersectWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;ToImmutable;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated", @@ -1281,8 +1337,13 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;set_KeyComparer;(System.Collections.Generic.IComparer);;Argument[0];Argument[this];taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>;false;Clear;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>;false;Intersect;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>;false;Remove;(T);;Argument[this];ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated", + "System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>;false;ToBuilder;();;Argument[this];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated", "System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated", @@ -1306,17 +1367,23 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections.Immutable;ImmutableStack<>;false;Push;(T);;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;Collection<>;false;Collection;(System.Collections.Generic.IList);;Argument[0].Element;Argument[this];taint;generated", "System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;Collection<>;false;get_Items;();;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;Collection<>;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;KeyedCollection;(System.Collections.Generic.IEqualityComparer,System.Int32);;Argument[0];Argument[this];taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;TryGetValue;(TKey,TItem);;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;KeyedCollection<,>;false;get_Dictionary;();;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.Collections.ObjectModel;ReadOnlyCollection<>;false;ReadOnlyCollection;(System.Collections.Generic.IList);;Argument[0].Element;Argument[this];taint;generated", "System.Collections.ObjectModel;ReadOnlyCollection<>;false;get_Items;();;Argument[this];ReturnValue;taint;generated", "System.Collections.ObjectModel;ReadOnlyCollection<>;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", @@ -1395,6 +1462,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections;BitArray;false;Xor;(System.Collections.BitArray);;Argument[this];ReturnValue;value;generated", "System.Collections;BitArray;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[0];Argument[this];taint;generated", + "System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[this];Argument[0];taint;generated", "System.Collections;CollectionBase;false;get_InnerList;();;Argument[this];ReturnValue;taint;generated", "System.Collections;CollectionBase;false;get_List;();;Argument[this];ReturnValue;taint;generated", "System.Collections;CollectionBase;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", @@ -1444,6 +1512,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Collections;Stack;false;Synchronized;(System.Collections.Stack);;Argument[0].Element;ReturnValue;taint;generated", "System.Collections;Stack;false;ToArray;();;Argument[this];ReturnValue;taint;generated", "System.Collections;Stack;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", + "System.ComponentModel.Composition.Hosting;AggregateCatalog;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AggregateCatalog;false;get_Catalogs;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AggregateExportProvider;false;AggregateExportProvider;(System.ComponentModel.Composition.Hosting.ExportProvider[]);;Argument[0].Element;Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;AggregateExportProvider;false;GetExportsCore;(System.ComponentModel.Composition.Primitives.ImportDefinition,System.ComponentModel.Composition.Hosting.AtomicComposition);;Argument[this];ReturnValue;taint;generated", @@ -1452,6 +1521,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel.Composition.Hosting;ApplicationCatalog;false;ApplicationCatalog;(System.Reflection.ReflectionContext);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;false;ApplicationCatalog;(System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;ApplicationCatalog;false;ApplicationCatalog;(System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[1];Argument[this];taint;generated", + "System.ComponentModel.Composition.Hosting;ApplicationCatalog;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.Reflection.Assembly);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.Reflection.Assembly,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.Reflection.Assembly,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[1];Argument[this];taint;generated", @@ -1464,6 +1534,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.String,System.Reflection.ReflectionContext);;Argument[1];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[1];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;AssemblyCatalog;(System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[2];Argument[this];taint;generated", + "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;get_Assembly;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;AssemblyCatalog;false;get_DisplayName;();;Argument[this];ReturnValue;taint;generated", @@ -1500,6 +1571,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;CompositionScopeDefinition;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog,System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;CompositionScopeDefinition;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog,System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;CompositionScopeDefinition;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog,System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[2].Element;Argument[this];taint;generated", + "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;get_Children;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;false;get_PublicSurface;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;DirectoryCatalog;(System.String,System.String);;Argument[0];Argument[this];taint;generated", @@ -1514,6 +1586,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;DirectoryCatalog;(System.String,System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[1];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;DirectoryCatalog;(System.String,System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[2];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;DirectoryCatalog;(System.String,System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[3];Argument[this];taint;generated", + "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;get_DisplayName;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;DirectoryCatalog;false;get_FullPath;();;Argument[this];ReturnValue;taint;generated", @@ -1532,12 +1605,14 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;false;get_AddedExports;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;false;get_ChangedContractNames;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;false;get_RemovedExports;();;Argument[this];ReturnValue;taint;generated", + "System.ComponentModel.Composition.Hosting;FilteredCatalog;false;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;FilteredCatalog;false;get_Complement;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Hosting;ImportEngine;false;ImportEngine;(System.ComponentModel.Composition.Hosting.ExportProvider,System.ComponentModel.Composition.Hosting.CompositionOptions);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;TypeCatalog;false;TypeCatalog;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;TypeCatalog;false;TypeCatalog;(System.Collections.Generic.IEnumerable,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[0].Element;Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;TypeCatalog;false;TypeCatalog;(System.Collections.Generic.IEnumerable,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[1];Argument[this];taint;generated", "System.ComponentModel.Composition.Hosting;TypeCatalog;false;TypeCatalog;(System.Collections.Generic.IEnumerable,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);;Argument[2];Argument[this];taint;generated", + "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;true;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Primitives;ComposablePartCatalog;true;get_Parts;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel.Composition.Primitives;ComposablePartException;false;ComposablePartException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[0];Argument[this];taint;generated", "System.ComponentModel.Composition.Primitives;ComposablePartException;false;ComposablePartException;(System.String,System.ComponentModel.Composition.Primitives.ICompositionElement,System.Exception);;Argument[1];Argument[this];taint;generated", @@ -1738,7 +1813,9 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel;BaseNumberConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[1];ReturnValue;taint;generated", "System.ComponentModel;BaseNumberConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated", "System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated", + "System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated", "System.ComponentModel;CategoryAttribute;false;CategoryAttribute;(System.String);;Argument[0];Argument[this];taint;generated", "System.ComponentModel;CategoryAttribute;false;get_Category;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel;CharConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated", @@ -1872,6 +1949,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.ComponentModel;ToolboxItemAttribute;false;get_ToolboxItemTypeName;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel;ToolboxItemFilterAttribute;false;get_TypeId;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this];Argument[0].Element;taint;generated", + "System.ComponentModel;TypeConverter+StandardValuesCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;false;StandardValuesCollection;(System.Collections.ICollection);;Argument[0].Element;Argument[this];taint;generated", "System.ComponentModel;TypeConverter+StandardValuesCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.ComponentModel;TypeConverter;false;ConvertFrom;(System.Object);;Argument[0];ReturnValue;taint;generated", @@ -2017,6 +2095,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Configuration.Internal;DelegatingConfigHost;false;GetStreamNameForConfigSource;(System.String,System.String);;Argument[0];ReturnValue;taint;generated", "System.Configuration.Internal;DelegatingConfigHost;false;GetStreamNameForConfigSource;(System.String,System.String);;Argument[1];ReturnValue;taint;generated", "System.Configuration.Internal;DelegatingConfigHost;false;InitForConfiguration;(System.String,System.String,System.String,System.Configuration.Internal.IInternalConfigRoot,System.Object[]);;Argument[4].Element;ReturnValue;taint;generated", + "System.Configuration.Internal;DelegatingConfigHost;false;OpenStreamForRead;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.Configuration.Internal;DelegatingConfigHost;false;OpenStreamForRead;(System.String,System.Boolean);;Argument[0];ReturnValue;taint;generated", "System.Configuration.Internal;DelegatingConfigHost;false;OpenStreamForWrite;(System.String,System.String,System.Object);;Argument[1];ReturnValue;taint;generated", "System.Configuration.Internal;DelegatingConfigHost;false;OpenStreamForWrite;(System.String,System.String,System.Object);;Argument[2];ReturnValue;taint;generated", "System.Configuration.Internal;DelegatingConfigHost;false;OpenStreamForWrite;(System.String,System.String,System.Object,System.Boolean);;Argument[1];ReturnValue;taint;generated", @@ -2334,6 +2414,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Common;DataTableMappingCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Data.Common;DbCommand;false;ExecuteReader;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommand;false;ExecuteReader;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated", + "System.Data.Common;DbCommand;false;ExecuteReaderAsync;();;Argument[this];ReturnValue;taint;generated", + "System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated", + "System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommand;false;get_Connection;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommand;false;get_Parameters;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommand;false;get_Transaction;();;Argument[this];ReturnValue;taint;generated", @@ -2341,6 +2425,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Common;DbCommand;false;set_Connection;(System.Data.IDbConnection);;Argument[0];Argument[this];taint;generated", "System.Data.Common;DbCommand;false;set_Transaction;(System.Data.Common.DbTransaction);;Argument[0];Argument[this];taint;generated", "System.Data.Common;DbCommand;false;set_Transaction;(System.Data.IDbTransaction);;Argument[0];Argument[this];taint;generated", + "System.Data.Common;DbCommand;true;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommand;true;PrepareAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;(System.Boolean);;Argument[this];ReturnValue;taint;generated", @@ -2367,6 +2452,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String);;Argument[2];Argument[0];taint;generated", "System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[1];Argument[0];taint;generated", "System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[2];Argument[0];taint;generated", + "System.Data.Common;DbConnectionStringBuilder;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbConnectionStringBuilder;false;GetProperties;();;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbConnectionStringBuilder;false;GetProperties;(System.Attribute[]);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbConnectionStringBuilder;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated", @@ -2393,9 +2479,12 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[0];ReturnValue;taint;generated", "System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[1];ReturnValue;taint;generated", "System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[3];ReturnValue;taint;generated", + "System.Data.Common;DbDataReader;false;GetFieldValueAsync<>;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbDataReader;true;GetFieldValue<>;(System.Int32);;Argument[this];ReturnValue;taint;generated", + "System.Data.Common;DbDataReader;true;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbDataReader;true;GetProviderSpecificValue;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbDataReader;true;GetProviderSpecificValues;(System.Object[]);;Argument[this];Argument[0].Element;taint;generated", + "System.Data.Common;DbDataReader;true;GetSchemaTableAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbDataReader;true;GetTextReader;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data.Common;DbDataRecord;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated", "System.Data.Common;DbEnumerator;false;DbEnumerator;(System.Data.IDataReader);;Argument[0];Argument[this];taint;generated", @@ -2540,6 +2629,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Odbc;OdbcParameter;false;set_Value;(System.Object);;Argument[0];Argument[this];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.Data.Odbc.OdbcParameter);;Argument[0];Argument[this];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.Data.Odbc.OdbcParameter);;Argument[0];ReturnValue;taint;generated", + "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.Data.Odbc.OdbcParameter);;Argument[this];Argument[0];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.String,System.Data.Odbc.OdbcType);;Argument[0];Argument[this];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.String,System.Data.Odbc.OdbcType);;Argument[0];ReturnValue;taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Add;(System.String,System.Data.Odbc.OdbcType,System.Int32);;Argument[0];Argument[this];taint;generated", @@ -2561,6 +2651,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data.Odbc;OdbcParameterCollection;false;GetParameter;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;GetParameter;(System.String);;Argument[this];ReturnValue;taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;Insert;(System.Int32,System.Data.Odbc.OdbcParameter);;Argument[1];Argument[this];taint;generated", + "System.Data.Odbc;OdbcParameterCollection;false;Insert;(System.Int32,System.Data.Odbc.OdbcParameter);;Argument[this];Argument[1];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;SetParameter;(System.Int32,System.Data.Common.DbParameter);;Argument[this];Argument[1];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;SetParameter;(System.String,System.Data.Common.DbParameter);;Argument[this];Argument[1];taint;generated", "System.Data.Odbc;OdbcParameterCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", @@ -2672,11 +2763,15 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data;DataColumn;false;set_Prefix;(System.String);;Argument[0];Argument[this];taint;generated", "System.Data;DataColumnChangeEventArgs;false;DataColumnChangeEventArgs;(System.Data.DataRow,System.Data.DataColumn,System.Object);;Argument[1];Argument[this];taint;generated", "System.Data;DataColumnChangeEventArgs;false;get_Column;();;Argument[this];ReturnValue;taint;generated", + "System.Data;DataColumnCollection;false;Add;();;Argument[this];ReturnValue;taint;generated", + "System.Data;DataColumnCollection;false;Add;(System.String,System.Type);;Argument[this];ReturnValue;taint;generated", + "System.Data;DataColumnCollection;false;Add;(System.String,System.Type,System.String);;Argument[this];ReturnValue;taint;generated", "System.Data;DataColumnCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data;DataColumnCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated", "System.Data;DataColumnCollection;false;get_List;();;Argument[this];ReturnValue;taint;generated", "System.Data;DataReaderExtensions;false;GetDateTime;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated", "System.Data;DataReaderExtensions;false;GetFieldValue<>;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated", + "System.Data;DataReaderExtensions;false;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);;Argument[0].Element;ReturnValue;taint;generated", "System.Data;DataReaderExtensions;false;GetGuid;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated", "System.Data;DataReaderExtensions;false;GetProviderSpecificValue;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated", "System.Data;DataReaderExtensions;false;GetString;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated", @@ -2706,10 +2801,16 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data;DataRelation;false;get_RelationName;();;Argument[this];ReturnValue;taint;generated", "System.Data;DataRelation;false;set_RelationName;(System.String);;Argument[0];Argument[this];taint;generated", "System.Data;DataRelationCollection;false;Remove;(System.Data.DataRelation);;Argument[0];Argument[this];taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated", "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];ReturnValue;taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[this];ReturnValue;taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated", "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];ReturnValue;taint;generated", + "System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[this];ReturnValue;taint;generated", "System.Data;DataRow;false;DataRow;(System.Data.DataRowBuilder);;Argument[0];Argument[this];taint;generated", "System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation);;Argument[this];ReturnValue;taint;generated", "System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation,System.Data.DataRowVersion);;Argument[this];ReturnValue;taint;generated", @@ -2807,8 +2908,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Data;DataTable;false;set_PrimaryKey;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this];taint;generated", "System.Data;DataTable;false;set_Site;(System.ComponentModel.ISite);;Argument[0];Argument[this];taint;generated", "System.Data;DataTable;false;set_TableName;(System.String);;Argument[0];Argument[this];taint;generated", + "System.Data;DataTableCollection;false;Add;();;Argument[this];ReturnValue;taint;generated", "System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];Argument[this];taint;generated", "System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];ReturnValue;taint;generated", + "System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[this];ReturnValue;taint;generated", "System.Data;DataTableCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Data;DataTableCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated", "System.Data;DataTableCollection;false;get_Item;(System.String,System.String);;Argument[this];ReturnValue;taint;generated", @@ -3111,20 +3214,29 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.DirectoryServices.Protocols;DirSyncRequestControl;false;DirSyncRequestControl;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirSyncRequestControl;false;set_Cookie;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.Byte[]);;Argument[this];Argument[0].Element;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.String);;Argument[0];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.String);;Argument[this];Argument[0];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.Uri);;Argument[0];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Add;(System.Uri);;Argument[this];Argument[0];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;AddRange;(System.Object[]);;Argument[0].Element;Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;CopyTo;(System.Object[],System.Int32);;Argument[this];Argument[0].Element;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;DirectoryAttribute;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;DirectoryAttribute;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;DirectoryAttribute;(System.String,System.Object[]);;Argument[this];Argument[1].Element;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;GetValues;(System.Type);;Argument[this];ReturnValue;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.Byte[]);;Argument[1].Element;Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.Byte[]);;Argument[this];Argument[1].Element;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.String);;Argument[1];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.String);;Argument[this];Argument[1];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.Uri);;Argument[1];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Insert;(System.Int32,System.Uri);;Argument[this];Argument[1];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;Remove;(System.Object);;Argument[0];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;Remove;(System.Object);;Argument[this];Argument[0];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;get_Name;();;Argument[this];ReturnValue;taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this];taint;generated", + "System.DirectoryServices.Protocols;DirectoryAttribute;false;set_Item;(System.Int32,System.Object);;Argument[this];Argument[1];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttribute;false;set_Name;(System.String);;Argument[0];Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttributeCollection;false;Add;(System.DirectoryServices.Protocols.DirectoryAttribute);;Argument[0].Element;Argument[this];taint;generated", "System.DirectoryServices.Protocols;DirectoryAttributeCollection;false;AddRange;(System.DirectoryServices.Protocols.DirectoryAttributeCollection);;Argument[0].Element;Argument[this];taint;generated", @@ -3313,18 +3425,22 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Drawing.Printing;PrintPageEventArgs;false;get_PageBounds;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrintPageEventArgs;false;get_PageSettings;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;false;Add;(System.Drawing.Printing.PaperSize);;Argument[0];Argument[this];taint;generated", + "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;false;PaperSizeCollection;(System.Drawing.Printing.PaperSize[]);;Argument[0].Element;Argument[this];taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSizeCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;false;Add;(System.Drawing.Printing.PaperSource);;Argument[0];Argument[this];taint;generated", + "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;false;PaperSourceCollection;(System.Drawing.Printing.PaperSource[]);;Argument[0].Element;Argument[this];taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PaperSourceCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;false;Add;(System.Drawing.Printing.PrinterResolution);;Argument[0];Argument[this];taint;generated", + "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;false;PrinterResolutionCollection;(System.Drawing.Printing.PrinterResolution[]);;Argument[0].Element;Argument[this];taint;generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Drawing.Printing;PrinterSettings+StringCollection;false;Add;(System.String);;Argument[0];Argument[this];taint;generated", + "System.Drawing.Printing;PrinterSettings+StringCollection;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+StringCollection;false;StringCollection;(System.String[]);;Argument[0].Element;Argument[this];taint;generated", "System.Drawing.Printing;PrinterSettings+StringCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;PrinterSettings+StringCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", @@ -3341,6 +3457,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Drawing.Printing;QueryPageSettingsEventArgs;false;get_PageSettings;();;Argument[this];ReturnValue;taint;generated", "System.Drawing.Printing;QueryPageSettingsEventArgs;false;set_PageSettings;(System.Drawing.Printing.PageSettings);;Argument[0];Argument[this];taint;generated", "System.Drawing.Printing;StandardPrintController;false;OnStartPage;(System.Drawing.Printing.PrintDocument,System.Drawing.Printing.PrintPageEventArgs);;Argument[1];ReturnValue;taint;generated", + "System.Drawing;Bitmap;false;Bitmap;(System.String,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Drawing;Bitmap;false;LockBits;(System.Drawing.Rectangle,System.Drawing.Imaging.ImageLockMode,System.Drawing.Imaging.PixelFormat,System.Drawing.Imaging.BitmapData);;Argument[3];ReturnValue;taint;generated", "System.Drawing;Brush;false;SetNativeBrush;(System.IntPtr);;Argument[0];Argument[this];taint;generated", "System.Drawing;BufferedGraphics;false;get_Graphics;();;Argument[this];ReturnValue;taint;generated", @@ -3378,6 +3495,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Drawing;Icon;false;Icon;(System.Drawing.Icon,System.Drawing.Size);;Argument[1];Argument[this];taint;generated", "System.Drawing;Icon;false;get_Handle;();;Argument[this];ReturnValue;taint;generated", "System.Drawing;Icon;false;get_Size;();;Argument[this];ReturnValue;taint;generated", + "System.Drawing;Image;false;FromFile;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.Drawing;Image;false;FromFile;(System.String,System.Boolean);;Argument[0];ReturnValue;taint;generated", "System.Drawing;Image;false;get_Tag;();;Argument[this];ReturnValue;taint;generated", "System.Drawing;Image;false;set_Tag;(System.Object);;Argument[0];Argument[this];taint;generated", "System.Drawing;ImageFormatConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated", @@ -3581,10 +3700,14 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO.Compression;BrotliStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO.Compression;BrotliStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;DeflateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.IO.Compression;DeflateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO.Compression;DeflateStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;DeflateStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;GZipStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO.Compression;GZipStream;false;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.IO.Compression;GZipStream;false;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode,System.Boolean);;Argument[0];Argument[this];taint;generated", + "System.IO.Compression;GZipStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO.Compression;GZipStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;GZipStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;ZLibException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated", "System.IO.Compression;ZLibException;false;ZLibException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[0];Argument[this];taint;generated", @@ -3609,7 +3732,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO.Compression;ZipArchiveEntry;false;get_Name;();;Argument[this];ReturnValue;taint;generated", "System.IO.Compression;ZipArchiveEntry;false;set_FullName;(System.String);;Argument[0];Argument[this];taint;generated", "System.IO.Compression;ZipArchiveEntry;false;set_LastWriteTime;(System.DateTimeOffset);;Argument[0];Argument[this];taint;generated", + "System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode);;Argument[0];ReturnValue;taint;generated", + "System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated", "System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[2];ReturnValue;taint;generated", + "System.IO.Compression;ZipFile;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated", "System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[0];ReturnValue;taint;generated", "System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[2];ReturnValue;taint;generated", "System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String,System.IO.Compression.CompressionLevel);;Argument[0];ReturnValue;taint;generated", @@ -3623,12 +3749,18 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO.IsolatedStorage;IsolatedStorage;false;get_AssemblyIdentity;();;Argument[this];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorage;false;get_DomainIdentity;();;Argument[this];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.IO.FileStream,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess,System.IO.HandleInheritability,System.Boolean);;Argument[0];ReturnValue;taint;generated", + "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated", + "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64);;Argument[0];ReturnValue;taint;generated", + "System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess);;Argument[0];ReturnValue;taint;generated", "System.IO.MemoryMappedFiles;MemoryMappedFile;false;get_SafeMemoryMappedFileHandle;();;Argument[this];ReturnValue;taint;generated", "System.IO.MemoryMappedFiles;MemoryMappedViewAccessor;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated", "System.IO.MemoryMappedFiles;MemoryMappedViewStream;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated", @@ -3743,6 +3875,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;BinaryReader;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[1];Argument[this];taint;generated", + "System.IO;BinaryWriter;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated", "System.IO;BinaryWriter;false;Write;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", "System.IO;BinaryWriter;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", "System.IO;BinaryWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", @@ -3782,8 +3915,19 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;File;false;AppendAllLinesAsync;(System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Text.Encoding,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated", "System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", + "System.IO;File;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;Create;(System.String,System.Int32);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;Create;(System.String,System.Int32,System.IO.FileOptions);;Argument[0];ReturnValue;taint;generated", "System.IO;File;false;CreateSymbolicLink;(System.String,System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;Open;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[0];ReturnValue;taint;generated", "System.IO;File;false;OpenHandle;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.Int64);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;OpenText;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;OpenWrite;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;ReadAllText;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;File;false;ReadAllText;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated", "System.IO;File;false;ReadLines;(System.String);;Argument[0];ReturnValue;taint;generated", "System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated", "System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[1];ReturnValue;taint;generated", @@ -3801,8 +3945,15 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;FileFormatException;false;get_SourceUri;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileInfo;false;CopyTo;(System.String);;Argument[0];ReturnValue;taint;generated", "System.IO;FileInfo;false;CopyTo;(System.String,System.Boolean);;Argument[0];ReturnValue;taint;generated", + "System.IO;FileInfo;false;Create;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileInfo;false;MoveTo;(System.String);;Argument[0];Argument[this];taint;generated", "System.IO;FileInfo;false;MoveTo;(System.String,System.Boolean);;Argument[0];Argument[this];taint;generated", + "System.IO;FileInfo;false;Open;(System.IO.FileMode);;Argument[this];ReturnValue;taint;generated", + "System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess);;Argument[this];ReturnValue;taint;generated", + "System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[this];ReturnValue;taint;generated", + "System.IO;FileInfo;false;OpenRead;();;Argument[this];ReturnValue;taint;generated", + "System.IO;FileInfo;false;OpenText;();;Argument[this];ReturnValue;taint;generated", + "System.IO;FileInfo;false;OpenWrite;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileInfo;false;get_Directory;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileInfo;false;get_DirectoryName;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileLoadException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated", @@ -3811,6 +3962,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;FileNotFoundException;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileNotFoundException;false;get_Message;();;Argument[this];ReturnValue;taint;generated", "System.IO;FileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.IO;FileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO;FileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO;FileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO;FileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", @@ -3867,14 +4019,24 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;RenamedEventArgs;false;RenamedEventArgs;(System.IO.WatcherChangeTypes,System.String,System.String,System.String);;Argument[3];Argument[this];taint;generated", "System.IO;RenamedEventArgs;false;get_OldFullPath;();;Argument[this];ReturnValue;taint;generated", "System.IO;RenamedEventArgs;false;get_OldName;();;Argument[this];ReturnValue;taint;generated", + "System.IO;Stream;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated", "System.IO;Stream;false;Synchronized;(System.IO.Stream);;Argument[0];ReturnValue;taint;generated", - "System.IO;StreamReader;false;StreamReader;(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32,System.Boolean);;Argument[0];Argument[this];taint;generated", - "System.IO;StreamReader;false;StreamReader;(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32,System.Boolean);;Argument[1];Argument[this];taint;generated", + "System.IO;Stream;true;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;Stream;true;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;Stream;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO;StreamReader;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO;StreamReader;false;get_CurrentEncoding;();;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated", "System.IO;StreamWriter;false;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.IO;StreamWriter;false;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32,System.Boolean);;Argument[1];Argument[this];taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated", "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object);;Argument[0];Argument[this];taint;generated", "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object);;Argument[1];Argument[this];taint;generated", "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object,System.Object);;Argument[0];Argument[this];taint;generated", @@ -3886,7 +4048,15 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated", "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated", "System.IO;StreamWriter;false;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;StreamWriter;false;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated", "System.IO;StreamWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.IO;StreamWriter;false;get_Encoding;();;Argument[this];ReturnValue;taint;generated", "System.IO;StringWriter;false;GetStringBuilder;();;Argument[this];ReturnValue;taint;generated", @@ -3894,19 +4064,29 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;StringWriter;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.IO;StringWriter;false;Write;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", "System.IO;StringWriter;false;Write;(System.String);;Argument[0];Argument[this];taint;generated", + "System.IO;StringWriter;false;Write;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated", "System.IO;StringWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", "System.IO;StringWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO;StringWriter;false;WriteAsync;(System.String);;Argument[0];Argument[this];taint;generated", + "System.IO;StringWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated", "System.IO;StringWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;StringWriter;false;WriteLine;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated", "System.IO;StringWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", "System.IO;StringWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO;StringWriter;false;WriteLineAsync;(System.String);;Argument[0];Argument[this];taint;generated", + "System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated", "System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO;TextReader;false;Synchronized;(System.IO.TextReader);;Argument[0];ReturnValue;taint;generated", "System.IO;TextWriter;false;Synchronized;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated", "System.IO;TextWriter;false;TextWriter;(System.IFormatProvider);;Argument[0];Argument[this];taint;generated", "System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated", + "System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated", + "System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;FlushAsync;();;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;Write;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated", "System.IO;TextWriter;true;Write;(System.Object);;Argument[0];Argument[this];taint;generated", "System.IO;TextWriter;true;Write;(System.String,System.Object);;Argument[0];Argument[this];taint;generated", @@ -3920,7 +4100,14 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;TextWriter;true;Write;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated", "System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated", "System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.IO;TextWriter;true;WriteLine;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated", "System.IO;TextWriter;true;WriteLine;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", @@ -3937,8 +4124,18 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.IO;TextWriter;true;WriteLine;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated", "System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated", "System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated", + "System.IO;TextWriter;true;WriteLine;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", + "System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;get_FormatProvider;();;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;get_NewLine;();;Argument[this];ReturnValue;taint;generated", "System.IO;TextWriter;true;set_NewLine;(System.String);;Argument[0];Argument[this];taint;generated", @@ -4537,6 +4734,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Http.Headers;HeaderStringValues;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http.Headers;HttpHeaders;false;get_NonValidated;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated", + "System.Net.Http.Headers;HttpHeadersNonValidated;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValue;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated", "System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValues;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated", "System.Net.Http.Headers;HttpHeadersNonValidated;false;get_Item;(System.String);;Argument[0];ReturnValue;taint;generated", @@ -4637,14 +4835,23 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", "System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated", "System.Net.Http;ByteArrayContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;ByteArrayContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;ByteArrayContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated", "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Http;DelegatingHandler;false;DelegatingHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated", "System.Net.Http;DelegatingHandler;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Http;DelegatingHandler;false;get_InnerHandler;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;DelegatingHandler;false;set_InnerHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated", + "System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage);;Argument[this];Argument[0];taint;generated", "System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption);;Argument[this];Argument[0];taint;generated", "System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", @@ -4671,7 +4878,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Http;HttpContent;false;ReadAsStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Http;HttpContent;false;get_Headers;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;HttpContent;true;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;HttpContent;true;CreateContentReadStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Http;HttpMessageInvoker;false;HttpMessageInvoker;(System.Net.Http.HttpMessageHandler,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Net.Http;HttpMessageInvoker;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Http;HttpMethod;false;HttpMethod;(System.String);;Argument[0];Argument[this];taint;generated", @@ -4706,6 +4916,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent,System.String,System.String);;Argument[0];Argument[this];taint;generated", "System.Net.Http;MultipartFormDataContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", "System.Net.Http;ReadOnlyMemoryContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;ReadOnlyMemoryContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;ReadOnlyMemoryContent;false;ReadOnlyMemoryContent;(System.ReadOnlyMemory);;Argument[0];Argument[this];taint;generated", "System.Net.Http;SocketsHttpConnectionContext;false;get_DnsEndPoint;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;SocketsHttpConnectionContext;false;get_InitialRequestMessage;();;Argument[this];ReturnValue;taint;generated", @@ -4744,11 +4955,19 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Http;SocketsHttpPlaintextStreamFilterContext;false;get_NegotiatedHttpVersion;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;SocketsHttpPlaintextStreamFilterContext;false;get_PlaintextStream;();;Argument[this];ReturnValue;taint;generated", "System.Net.Http;StreamContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated", "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated", + "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", "System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream,System.Int32);;Argument[0];Argument[this];taint;generated", + "System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated", + "System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String);;Argument[0];ReturnValue;taint;generated", "System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[0];ReturnValue;taint;generated", "System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[1];ReturnValue;taint;generated", @@ -4778,7 +4997,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated", "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated", "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.String);;Argument[0];Argument[this];taint;generated", + "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String);;Argument[0];Argument[this];taint;generated", + "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated", "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated", + "System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.String);;Argument[0];Argument[this];taint;generated", "System.Net.Mail;AttachmentBase;false;get_ContentId;();;Argument[this];ReturnValue;taint;generated", "System.Net.Mail;AttachmentBase;false;get_ContentStream;();;Argument[this];ReturnValue;taint;generated", "System.Net.Mail;AttachmentBase;false;set_ContentType;(System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated", @@ -4881,6 +5103,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Quic;QuicListener;false;QuicListener;(System.Net.Quic.Implementations.QuicImplementationProvider,System.Net.Quic.QuicListenerOptions);;Argument[1];Argument[this];taint;generated", "System.Net.Quic;QuicListener;false;get_ListenEndPoint;();;Argument[this];ReturnValue;taint;generated", "System.Net.Security;AuthenticatedStream;false;AuthenticatedStream;(System.IO.Stream,System.Boolean);;Argument[0];Argument[this];taint;generated", + "System.Net.Security;AuthenticatedStream;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated", "System.Net.Security;AuthenticatedStream;false;get_InnerStream;();;Argument[this];ReturnValue;taint;generated", "System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[1];Argument[this];taint;generated", "System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[2];Argument[this];taint;generated", @@ -4899,6 +5122,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Security;NegotiateStream;false;AuthenticateAsServerAsync;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy,System.Net.Security.ProtectionLevel,System.Security.Principal.TokenImpersonationLevel);;Argument[1];Argument[this];taint;generated", "System.Net.Security;NegotiateStream;false;AuthenticateAsServerAsync;(System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy);;Argument[0];Argument[this];taint;generated", "System.Net.Security;NegotiateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Security;NegotiateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", @@ -4911,6 +5135,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Security;SslCertificateTrust;false;CreateForX509Collection;(System.Security.Cryptography.X509Certificates.X509Certificate2Collection,System.Boolean);;Argument[0].Element;ReturnValue;taint;generated", "System.Net.Security;SslCertificateTrust;false;CreateForX509Store;(System.Security.Cryptography.X509Certificates.X509Store,System.Boolean);;Argument[0];ReturnValue;taint;generated", "System.Net.Security;SslStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Net.Security;SslStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Security;SslStream;false;Write;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated", "System.Net.Security;SslStream;false;get_LocalCertificate;();;Argument[this];ReturnValue;taint;generated", "System.Net.Security;SslStream;false;get_NegotiatedApplicationProtocol;();;Argument[this];ReturnValue;taint;generated", @@ -4941,6 +5166,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;NetworkStream;false;get_Socket;();;Argument[this];ReturnValue;taint;generated", "System.Net.Sockets;SafeSocketHandle;false;SafeSocketHandle;(System.IntPtr,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Net.Sockets;Socket;false;Accept;();;Argument[this];ReturnValue;taint;generated", + "System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", @@ -4964,6 +5190,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;DisconnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);;Argument[this];Argument[0];taint;generated", + "System.Net.Sockets;Socket;false;EndAccept;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", @@ -4983,6 +5210,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.EndPoint);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];Argument[this];taint;generated", "System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated", + "System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.ArraySegment,System.Net.EndPoint);;Argument[1];ReturnValue;taint;generated", + "System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", @@ -4996,6 +5225,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[4];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];Argument[this];taint;generated", "System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];ReturnValue;taint;generated", + "System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.EndPoint);;Argument[1];ReturnValue;taint;generated", + "System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated", @@ -5054,6 +5285,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;SocketAsyncEventArgs;false;set_SendPacketsElements;(System.Net.Sockets.SendPacketsElement[]);;Argument[0].Element;Argument[this];taint;generated", "System.Net.Sockets;SocketAsyncEventArgs;false;set_UserToken;(System.Object);;Argument[0];Argument[this];taint;generated", "System.Net.Sockets;SocketException;false;get_Message;();;Argument[this];ReturnValue;taint;generated", + "System.Net.Sockets;SocketTaskExtensions;false;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint);;Argument[1];Argument[0];taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated", @@ -5065,6 +5297,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated", + "System.Net.Sockets;SocketTaskExtensions;false;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated", + "System.Net.Sockets;SocketTaskExtensions;false;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated", "System.Net.Sockets;SocketTaskExtensions;false;SendToAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];Argument[0];taint;generated", @@ -5079,6 +5313,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Net.Sockets;TcpListener;false;AcceptTcpClient;();;Argument[this];ReturnValue;taint;generated", + "System.Net.Sockets;TcpListener;false;EndAcceptSocket;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net.Sockets;TcpListener;false;EndAcceptTcpClient;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", "System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPAddress,System.Int32);;Argument[0];Argument[this];taint;generated", "System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPEndPoint);;Argument[0];Argument[this];taint;generated", "System.Net.Sockets;TcpListener;false;get_LocalEndpoint;();;Argument[this];ReturnValue;taint;generated", @@ -5163,11 +5399,17 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net;CookieCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Net;CookieException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated", "System.Net;CredentialCache;false;GetCredential;(System.Uri,System.String);;Argument[this];ReturnValue;taint;generated", + "System.Net;Dns;false;EndGetHostAddresses;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;Dns;false;EndGetHostByName;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;Dns;false;EndGetHostEntry;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;Dns;false;EndResolve;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", "System.Net;DnsEndPoint;false;DnsEndPoint;(System.String,System.Int32,System.Net.Sockets.AddressFamily);;Argument[0];Argument[this];taint;generated", "System.Net;DnsEndPoint;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.Net;DnsEndPoint;false;get_Host;();;Argument[this];ReturnValue;taint;generated", "System.Net;DownloadDataCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated", "System.Net;DownloadStringCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated", + "System.Net;FileWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;FileWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", "System.Net;FileWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated", "System.Net;FileWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated", "System.Net;FileWebRequest;false;get_ContentType;();;Argument[this];ReturnValue;taint;generated", @@ -5241,6 +5483,9 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net;HttpListenerTimeoutManager;false;get_IdleConnection;();;Argument[this];ReturnValue;taint;generated", "System.Net;HttpListenerTimeoutManager;false;set_DrainEntityBody;(System.TimeSpan);;Argument[0];Argument[this];taint;generated", "System.Net;HttpListenerTimeoutManager;false;set_IdleConnection;(System.TimeSpan);;Argument[0];Argument[this];taint;generated", + "System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated", + "System.Net;HttpWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", "System.Net;HttpWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated", "System.Net;HttpWebRequest;false;GetRequestStream;(System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated", "System.Net;HttpWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated", @@ -5297,6 +5542,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net;OpenWriteCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated", "System.Net;PathList;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated", "System.Net;PathList;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", + "System.Net;PathList;false;get_Values;();;Argument[this];ReturnValue;taint;generated", "System.Net;ProtocolViolationException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated", "System.Net;UploadDataCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated", "System.Net;UploadFileCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated", @@ -5326,6 +5572,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest);;Argument[0];ReturnValue;taint;generated", "System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];Argument[this];taint;generated", "System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];ReturnValue;taint;generated", + "System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];Argument[this];taint;generated", + "System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];ReturnValue;taint;generated", "System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];Argument[this];taint;generated", "System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated", "System.Net;WebClient;false;OpenRead;(System.String);;Argument[this];ReturnValue;taint;generated", @@ -5486,7 +5734,6 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Numerics;BigInteger;false;Max;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated", - "System.Numerics;BigInteger;false;Negate;(System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;Pow;(System.Numerics.BigInteger,System.Int32);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;Remainder;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;op_BitwiseOr;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", @@ -5494,7 +5741,6 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Numerics;BigInteger;false;op_LeftShift;(System.Numerics.BigInteger,System.Int32);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;op_Modulus;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;op_RightShift;(System.Numerics.BigInteger,System.Int32);;Argument[0];ReturnValue;taint;generated", - "System.Numerics;BigInteger;false;op_UnaryNegation;(System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;BigInteger;false;op_UnaryPlus;(System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated", "System.Numerics;Complex;false;ToString;(System.IFormatProvider);;Argument[0];ReturnValue;taint;generated", "System.Numerics;Complex;false;ToString;(System.String,System.IFormatProvider);;Argument[1];ReturnValue;taint;generated", @@ -6224,6 +6470,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Resources.Extensions;DeserializingResourceReader;false;DeserializingResourceReader;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", "System.Resources.Extensions;DeserializingResourceReader;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Resources.Extensions;PreserializedResourceWriter;false;PreserializedResourceWriter;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", + "System.Resources.Extensions;PreserializedResourceWriter;false;PreserializedResourceWriter;(System.String);;Argument[0];Argument[this];taint;generated", "System.Resources;MissingSatelliteAssemblyException;false;MissingSatelliteAssemblyException;(System.String,System.String);;Argument[1];Argument[this];taint;generated", "System.Resources;MissingSatelliteAssemblyException;false;get_CultureName;();;Argument[this];ReturnValue;taint;generated", "System.Resources;ResourceManager;false;CreateFileBasedResourceManager;(System.String,System.String,System.Type);;Argument[0];ReturnValue;taint;generated", @@ -6241,9 +6488,11 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Resources;ResourceReader;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Resources;ResourceReader;false;GetResourceData;(System.String,System.String,System.Byte[]);;Argument[this];ReturnValue;taint;generated", "System.Resources;ResourceReader;false;ResourceReader;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", + "System.Resources;ResourceSet;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Resources;ResourceSet;false;ResourceSet;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", "System.Resources;ResourceSet;false;ResourceSet;(System.Resources.IResourceReader);;Argument[0].Element;Argument[this];taint;generated", "System.Resources;ResourceWriter;false;ResourceWriter;(System.IO.Stream);;Argument[0];Argument[this];taint;generated", + "System.Resources;ResourceWriter;false;ResourceWriter;(System.String);;Argument[0];Argument[this];taint;generated", "System.Runtime.Caching;CacheEntryRemovedArguments;false;CacheEntryRemovedArguments;(System.Runtime.Caching.ObjectCache,System.Runtime.Caching.CacheEntryRemovedReason,System.Runtime.Caching.CacheItem);;Argument[0].Element;Argument[this];taint;generated", "System.Runtime.Caching;CacheEntryRemovedArguments;false;CacheEntryRemovedArguments;(System.Runtime.Caching.ObjectCache,System.Runtime.Caching.CacheEntryRemovedReason,System.Runtime.Caching.CacheItem);;Argument[2];Argument[this];taint;generated", "System.Runtime.Caching;CacheEntryRemovedArguments;false;get_CacheItem;();;Argument[this];ReturnValue;taint;generated", @@ -6308,8 +6557,6 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider);;Argument[2];Argument[this];taint;generated", "System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[2];Argument[this];taint;generated", "System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[3];Argument[this];taint;generated", - "System.Runtime.CompilerServices;DynamicAttribute;false;DynamicAttribute;(System.Boolean[]);;Argument[0].Element;Argument[this];taint;generated", - "System.Runtime.CompilerServices;DynamicAttribute;false;get_TransformFlags;();;Argument[this];ReturnValue;taint;generated", "System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[0];ReturnValue;taint;generated", "System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[1].Element;ReturnValue;taint;generated", "System.Runtime.CompilerServices;PoolingAsyncValueTaskMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated", @@ -6321,13 +6568,11 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;ReadOnlyCollectionBuilder;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated", "System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated", "System.Runtime.CompilerServices;RuntimeOps;false;CreateRuntimeVariables;(System.Object[],System.Int64[]);;Argument[0].Element;ReturnValue;taint;generated", - "System.Runtime.CompilerServices;RuntimeOps;false;CreateRuntimeVariables;(System.Object[],System.Int64[]);;Argument[1].Element;ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;ExpandoPromoteClass;(System.Dynamic.ExpandoObject,System.Object,System.Object);;Argument[2];Argument[0].Element;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;ExpandoTryGetValue;(System.Dynamic.ExpandoObject,System.Object,System.Int32,System.String,System.Boolean,System.Object);;Argument[0].Element;ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;ExpandoTrySetValue;(System.Dynamic.ExpandoObject,System.Object,System.Int32,System.Object,System.String,System.Boolean);;Argument[3];ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;MergeRuntimeVariables;(System.Runtime.CompilerServices.IRuntimeVariables,System.Runtime.CompilerServices.IRuntimeVariables,System.Int32[]);;Argument[0];ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;MergeRuntimeVariables;(System.Runtime.CompilerServices.IRuntimeVariables,System.Runtime.CompilerServices.IRuntimeVariables,System.Int32[]);;Argument[1];ReturnValue;taint;generated", - "System.Runtime.CompilerServices;RuntimeOps;false;MergeRuntimeVariables;(System.Runtime.CompilerServices.IRuntimeVariables,System.Runtime.CompilerServices.IRuntimeVariables,System.Int32[]);;Argument[2].Element;ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeOps;false;Quote;(System.Linq.Expressions.Expression,System.Object,System.Object[]);;Argument[0];ReturnValue;taint;generated", "System.Runtime.CompilerServices;RuntimeWrappedException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated", "System.Runtime.CompilerServices;RuntimeWrappedException;false;RuntimeWrappedException;(System.Object);;Argument[0];Argument[this];taint;generated", @@ -6651,6 +6896,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Security.Cryptography.Pkcs;Pkcs12SafeBag;false;set_Attributes;(System.Security.Cryptography.CryptographicAttributeObjectCollection);;Argument[0].Element;Argument[this];taint;generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;false;AddSafeBag;(System.Security.Cryptography.Pkcs.Pkcs12SafeBag);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;false;AddSecret;(System.Security.Cryptography.Oid,System.ReadOnlyMemory);;Argument[0];ReturnValue;taint;generated", + "System.Security.Cryptography.Pkcs;Pkcs12SafeContents;false;GetBags;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Pkcs;Pkcs12SecretBag;false;GetSecretType;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Pkcs;Pkcs12SecretBag;false;get_SecretValue;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Pkcs;Pkcs9AttributeObject;false;CopyFrom;(System.Security.Cryptography.AsnEncodedData);;Argument[0];Argument[this];taint;generated", @@ -6737,6 +6983,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Security.Cryptography.X509Certificates;X509Certificate;false;ToString;(System.Boolean);;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Issuer;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Subject;();;Argument[this];ReturnValue;taint;generated", + "System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this];taint;generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;Remove;(System.Security.Cryptography.X509Certificates.X509Certificate);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;X509CertificateCollection;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this];taint;generated", @@ -6857,6 +7104,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;set_ItemOf;(System.Int32,System.Security.Cryptography.Xml.EncryptionProperty);;Argument[1];Argument[this];taint;generated", "System.Security.Cryptography.Xml;KeyInfo;false;AddClause;(System.Security.Cryptography.Xml.KeyInfoClause);;Argument[0];Argument[this];taint;generated", + "System.Security.Cryptography.Xml;KeyInfo;false;GetEnumerator;(System.Type);;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Xml;KeyInfo;false;LoadXml;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated", "System.Security.Cryptography.Xml;KeyInfo;false;get_Id;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Xml;KeyInfo;false;set_Id;(System.String);;Argument[0];Argument[this];taint;generated", @@ -6969,6 +7217,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Security.Cryptography.Xml;Transform;false;set_Context;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated", "System.Security.Cryptography.Xml;Transform;false;set_Resolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography.Xml;TransformChain;false;Add;(System.Security.Cryptography.Xml.Transform);;Argument[0];Argument[this];taint;generated", + "System.Security.Cryptography.Xml;TransformChain;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Xml;TransformChain;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography.Xml;XmlDecryptionTransform;false;AddExceptUri;(System.String);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography.Xml;XmlDecryptionTransform;false;GetOutput;();;Argument[this];ReturnValue;taint;generated", @@ -7034,6 +7283,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Security.Cryptography;CryptoStream;false;CryptoStream;(System.IO.Stream,System.Security.Cryptography.ICryptoTransform,System.Security.Cryptography.CryptoStreamMode,System.Boolean);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography;CryptoStream;false;CryptoStream;(System.IO.Stream,System.Security.Cryptography.ICryptoTransform,System.Security.Cryptography.CryptoStreamMode,System.Boolean);;Argument[1];Argument[this];taint;generated", "System.Security.Cryptography;CryptoStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Security.Cryptography;CryptoStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography;CryptographicAttributeObject;false;CryptographicAttributeObject;(System.Security.Cryptography.Oid,System.Security.Cryptography.AsnEncodedDataCollection);;Argument[0];Argument[this];taint;generated", "System.Security.Cryptography;CryptographicAttributeObject;false;get_Oid;();;Argument[this];ReturnValue;taint;generated", "System.Security.Cryptography;CryptographicAttributeObjectCollection;false;Add;(System.Security.Cryptography.CryptographicAttributeObject);;Argument[0];Argument[this];taint;generated", @@ -7298,6 +7548,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Text.Encodings.Web;TextEncoder;true;Encode;(System.IO.TextWriter,System.String,System.Int32,System.Int32);;Argument[1];Argument[0];taint;generated", "System.Text.Encodings.Web;TextEncoder;true;Encode;(System.String);;Argument[0];ReturnValue;taint;generated", "System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[0];Argument[this];taint;generated", + "System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[this];Argument[0];taint;generated", "System.Text.Json.Nodes;JsonArray;false;Create;(System.Text.Json.JsonElement,System.Nullable);;Argument[0];ReturnValue;taint;generated", "System.Text.Json.Nodes;JsonArray;false;JsonArray;(System.Text.Json.Nodes.JsonNodeOptions,System.Text.Json.Nodes.JsonNode[]);;Argument[this];Argument[1].Element;taint;generated", "System.Text.Json.Nodes;JsonArray;false;JsonArray;(System.Text.Json.Nodes.JsonNode[]);;Argument[this];Argument[0].Element;taint;generated", @@ -7317,6 +7568,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Text.Json.Serialization;JsonSerializerContext;false;JsonSerializerContext;(System.Text.Json.JsonSerializerOptions);;Argument[this];Argument[0];taint;generated", "System.Text.Json.Serialization;JsonSerializerContext;false;get_Options;();;Argument[this];ReturnValue;taint;generated", "System.Text.Json.Serialization;JsonStringEnumConverter;false;JsonStringEnumConverter;(System.Text.Json.JsonNamingPolicy,System.Boolean);;Argument[0];Argument[this];taint;generated", + "System.Text.Json.SourceGeneration;JsonSourceGenerator;false;GetSerializableTypes;();;Argument[this];ReturnValue;taint;generated", "System.Text.Json;JsonDocument;false;Parse;(System.Buffers.ReadOnlySequence,System.Text.Json.JsonDocumentOptions);;Argument[0];ReturnValue;taint;generated", "System.Text.Json;JsonDocument;false;Parse;(System.IO.Stream,System.Text.Json.JsonDocumentOptions);;Argument[0];ReturnValue;taint;generated", "System.Text.Json;JsonDocument;false;Parse;(System.ReadOnlyMemory,System.Text.Json.JsonDocumentOptions);;Argument[0];ReturnValue;taint;generated", @@ -7541,6 +7793,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Threading.RateLimiting;MetadataName<>;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System.Threading.RateLimiting;MetadataName<>;false;get_Name;();;Argument[this];ReturnValue;taint;generated", "System.Threading.RateLimiting;RateLimitLease;false;TryGetMetadata<>;(System.Threading.RateLimiting.MetadataName,T);;Argument[this];ReturnValue;taint;generated", + "System.Threading.RateLimiting;RateLimitLease;true;GetAllMetadata;();;Argument[this];ReturnValue;taint;generated", "System.Threading.RateLimiting;RateLimiter;false;Acquire;(System.Int32);;Argument[this];ReturnValue;taint;generated", "System.Threading.RateLimiting;RateLimiter;false;WaitAsync;(System.Int32,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated", "System.Threading.RateLimiting;TokenBucketRateLimiter;false;TokenBucketRateLimiter;(System.Threading.RateLimiting.TokenBucketRateLimiterOptions);;Argument[0];Argument[this];taint;generated", @@ -7582,6 +7835,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated", "System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);;Argument[0];ReturnValue;taint;generated", + "System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", + "System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated", + "System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated", "System.Threading.Tasks.Dataflow;DataflowBlock;false;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock,TInput,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated", "System.Threading.Tasks.Dataflow;DataflowBlock;false;TryReceive<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock,TOutput);;Argument[0];ReturnValue;taint;generated", "System.Threading.Tasks.Dataflow;DataflowBlockOptions;false;get_CancellationToken;();;Argument[this];ReturnValue;taint;generated", @@ -7957,6 +8214,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml.Linq;XText;false;XText;(System.Xml.Linq.XText);;Argument[0];Argument[this];taint;generated", "System.Xml.Linq;XText;false;get_Value;();;Argument[this];ReturnValue;taint;generated", "System.Xml.Linq;XText;false;set_Value;(System.String);;Argument[0];Argument[this];taint;generated", + "System.Xml.Resolvers;XmlPreloadedResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated", "System.Xml.Resolvers;XmlPreloadedResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated", "System.Xml.Resolvers;XmlPreloadedResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated", "System.Xml.Resolvers;XmlPreloadedResolver;false;XmlPreloadedResolver;(System.Xml.XmlResolver,System.Xml.Resolvers.XmlKnownDtds,System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated", @@ -8177,9 +8435,12 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml.Schema;XmlSchemaSet;false;Add;(System.String,System.Xml.XmlReader);;Argument[this];ReturnValue;taint;generated", "System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated", "System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated", + "System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchemaSet);;Argument[0];Argument[this];taint;generated", + "System.Xml.Schema;XmlSchemaSet;false;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);;Argument[this];Argument[0].Element;taint;generated", "System.Xml.Schema;XmlSchemaSet;false;Remove;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated", "System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated", "System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated", + "System.Xml.Schema;XmlSchemaSet;false;Schemas;();;Argument[this];ReturnValue;taint;generated", "System.Xml.Schema;XmlSchemaSet;false;XmlSchemaSet;(System.Xml.XmlNameTable);;Argument[0];Argument[this];taint;generated", "System.Xml.Schema;XmlSchemaSet;false;get_CompilationSettings;();;Argument[this];ReturnValue;taint;generated", "System.Xml.Schema;XmlSchemaSet;false;get_GlobalAttributes;();;Argument[this];ReturnValue;taint;generated", @@ -8266,8 +8527,10 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml.Schema;XmlSchemaXPath;false;get_XPath;();;Argument[this];ReturnValue;taint;generated", "System.Xml.Schema;XmlSchemaXPath;false;set_XPath;(System.String);;Argument[0];Argument[this];taint;generated", "System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[1];Argument[this];taint;generated", + "System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[this];Argument[1];taint;generated", "System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[0];ReturnValue;taint;generated", "System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[1];Argument[this];taint;generated", + "System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[this];Argument[1];taint;generated", "System.Xml.Serialization;CodeIdentifiers;false;MakeUnique;(System.String);;Argument[0];ReturnValue;taint;generated", "System.Xml.Serialization;CodeIdentifiers;false;ToArray;(System.Type);;Argument[this];ReturnValue;taint;generated", "System.Xml.Serialization;ImportContext;false;ImportContext;(System.Xml.Serialization.CodeIdentifiers,System.Boolean);;Argument[0];Argument[this];taint;generated", @@ -8550,6 +8813,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.Xml.XmlQualifiedName);;Argument[1];Argument[this];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WriteId;(System.Object);;Argument[this];Argument[0];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncoded;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.Byte[],System.Xml.XmlQualifiedName);;Argument[2].Element;Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated", @@ -8557,9 +8821,15 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.Byte[]);;Argument[2].Element;Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[2];Argument[this];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[2];Argument[this];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[this];Argument[2];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[2];Argument[this];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[this];Argument[2];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[2];Argument[this];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[this];Argument[2];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated", + "System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);;Argument[this];Argument[2];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[0];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[1];Argument[this];taint;generated", "System.Xml.Serialization;XmlSerializationWriter;false;WriteSerializable;(System.Xml.Serialization.IXmlSerializable,System.String,System.String,System.Boolean);;Argument[0];Argument[this];taint;generated", @@ -9306,6 +9576,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml;XmlReaderSettings;false;set_XmlResolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated", "System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated", + "System.Xml;XmlSecureResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlSecureResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlSecureResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated", "System.Xml;XmlSecureResolver;false;XmlSecureResolver;(System.Xml.XmlResolver,System.String);;Argument[0];Argument[this];taint;generated", @@ -9335,6 +9606,7 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml;XmlTextWriter;false;XmlTextWriter;(System.IO.TextWriter);;Argument[0];Argument[this];taint;generated", "System.Xml;XmlTextWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated", "System.Xml;XmlTextWriter;false;get_XmlLang;();;Argument[this];ReturnValue;taint;generated", + "System.Xml;XmlUrlResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlUrlResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlUrlResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated", "System.Xml;XmlUrlResolver;false;set_Credentials;(System.Net.ICredentials);;Argument[0];Argument[this];taint;generated", @@ -9354,6 +9626,8 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System.Xml;XmlWriter;false;Create;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated", + "System.Xml;XmlWriter;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated", + "System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated", "System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated", "System.Xml;XmlWriter;false;Create;(System.Text.StringBuilder,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated", "System.Xml;XmlWriter;false;Create;(System.Xml.XmlWriter);;Argument[0];ReturnValue;taint;generated", @@ -9736,6 +10010,27 @@ private class RuntimeSummaryCsv extends SummaryModelCsv { "System;Tuple<,>;false;get_Item2;();;Argument[this];ReturnValue;taint;generated", "System;Tuple<>;false;ToString;();;Argument[this];ReturnValue;taint;generated", "System;Tuple<>;false;get_Item1;();;Argument[this];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", + "System;TupleExtensions;false;ToTuple<>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated", "System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated", "System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated", "System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/VisualBasic.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/VisualBasic.qll index 721ce089846..74954bcc200 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/VisualBasic.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/VisualBasic.qll @@ -7,6 +7,7 @@ private class MicrosoftVisualBasicCollectionFlowModelCsv extends SummaryModelCsv override predicate row(string row) { row = [ + "Microsoft.VisualBasic;Collection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "Microsoft.VisualBasic;Collection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual", "Microsoft.VisualBasic;Collection;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual", "Microsoft.VisualBasic;Collection;false;get_Item;(System.Object);;Argument[this].Element;ReturnValue;value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/CodeDom.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/CodeDom.qll index 400e9954866..2688f14a3fe 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/CodeDom.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/CodeDom.qll @@ -2,6 +2,7 @@ import csharp private import semmle.code.csharp.frameworks.System +private import semmle.code.csharp.dataflow.ExternalFlow /** The `System.CodeDome` namespace. */ class SystemCodeDomNamespace extends Namespace { @@ -10,3 +11,11 @@ class SystemCodeDomNamespace extends Namespace { this.hasName("CodeDom") } } + +/** Data flow for `System.CodeDom.CodeNamespaceImportCollection`. */ +private class SystemCodeDomCodeNamespaceImportCollectionFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.CodeDom;CodeNamespaceImportCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Collections.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Collections.qll index f5ca63d3eb6..7a12a1546ef 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Collections.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Collections.qll @@ -46,20 +46,6 @@ private class SystemCollectionIEnumerableFlowModelCsv extends SummaryModelCsv { } } -/** Clear content for Clear methods in all subtypes of `System.Collections.IEnumerable`. */ -private class SystemCollectionsIEnumerableClearFlow extends SummarizedCallable { - SystemCollectionsIEnumerableClearFlow() { - this.getDeclaringType().(RefType).getABaseType*() instanceof - SystemCollectionsIEnumerableInterface and - this.hasName("Clear") - } - - override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { - (if this.(Modifiable).isStatic() then pos.getPosition() = 0 else pos.isThisParameter()) and - content instanceof DataFlow::ElementContent - } -} - /** The `System.Collections.IEnumerator` interface. */ class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface { SystemCollectionsIEnumeratorInterface() { this.hasName("IEnumerator") } @@ -96,6 +82,7 @@ private class SystemCollectionsIListFlowModelCsv extends SummaryModelCsv { row = [ "System.Collections;IList;true;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual", + "System.Collections;IList;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections;IList;true;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual", "System.Collections;IList;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual", "System.Collections;IList;true;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual", @@ -115,6 +102,7 @@ private class SystemCollectionsIDictionaryFlowModelCsv extends SummaryModelCsv { [ "System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual", "System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual", + "System.Collections;IDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections;IDictionary;true;get_Item;(System.Object);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual", "System.Collections;IDictionary;true;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual", "System.Collections;IDictionary;true;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual", @@ -194,6 +182,7 @@ private class SystemCollectionsQueueFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = [ + "System.Collections;Queue;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections;Queue;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual", "System.Collections;Queue;false;Peek;();;Argument[this].Element;ReturnValue;value;manual", ] @@ -205,6 +194,7 @@ private class SystemCollectionsStackFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = [ + "System.Collections;Stack;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections;Stack;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual", "System.Collections;Stack;false;Peek;();;Argument[this].Element;ReturnValue;value;manual", "System.Collections;Stack;false;Pop;();;Argument[this].Element;ReturnValue;value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/ComponentModel.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/ComponentModel.qll index 3eb5de6fd6f..fee6e5ce86d 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/ComponentModel.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/ComponentModel.qll @@ -12,6 +12,7 @@ private class SystemComponentModelPropertyDescriptorCollectionFlowModelCsv exten "System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.ComponentModel.PropertyDescriptor);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual", "System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual", "System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual", + "System.ComponentModel;PropertyDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.ComponentModel;PropertyDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual", "System.ComponentModel;PropertyDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual", "System.ComponentModel;PropertyDescriptorCollection;false;Insert;(System.Int32,System.ComponentModel.PropertyDescriptor);;Argument[1];Argument[this].Element;value;manual", @@ -37,6 +38,7 @@ private class SystemComponentModelEventDescriptorCollectionFlowModelCsv extends row = [ "System.ComponentModel;EventDescriptorCollection;false;Add;(System.ComponentModel.EventDescriptor);;Argument[0];Argument[this].Element;value;manual", + "System.ComponentModel;EventDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.ComponentModel;EventDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual", "System.ComponentModel;EventDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual", "System.ComponentModel;EventDescriptorCollection;false;Insert;(System.Int32,System.ComponentModel.EventDescriptor);;Argument[1];Argument[this].Element;value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Configuration.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Configuration.qll new file mode 100644 index 00000000000..ab28ed772bd --- /dev/null +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Configuration.qll @@ -0,0 +1,26 @@ +/** Provides definitions related to the namespace `System.Configuration`. */ + +import csharp +private import semmle.code.csharp.dataflow.ExternalFlow + +/** Data flow for some collection classes in `System.Configuration.*`. */ +private class SystemClearFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "System.Configuration;CommaDelimitedStringCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ConfigurationLockCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ConfigurationPropertyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ConfigurationSectionCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ConfigurationSectionGroupCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ConnectionStringSettingsCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;KeyValueConfigurationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;NameValueConfigurationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;ProviderSettingsCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;SettingElementCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;SettingsPropertyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration;SettingsPropertyValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Configuration.Provider;ProviderCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + ] + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Data.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Data.qll index bc671003a42..0c91f35cbcd 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Data.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Data.qll @@ -150,6 +150,7 @@ private class SystemDataConstraintCollectionFlowModelCsv extends SummaryModelCsv [ "System.Data;ConstraintCollection;false;Add;(System.Data.Constraint);;Argument[0];Argument[this].Element;value;manual", "System.Data;ConstraintCollection;false;AddRange;(System.Data.Constraint[]);;Argument[0].Element;Argument[this].Element;value;manual", + "System.Data;ConstraintCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Data;ConstraintCollection;false;CopyTo;(System.Data.Constraint[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", ] } @@ -163,6 +164,7 @@ private class SystemDataDataColumnCollectionFlowModelCsv extends SummaryModelCsv "System.Data;DataColumnCollection;false;Add;(System.Data.DataColumn);;Argument[0];Argument[this].Element;value;manual", "System.Data;DataColumnCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual", "System.Data;DataColumnCollection;false;AddRange;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this].Element;value;manual", + "System.Data;DataColumnCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Data;DataColumnCollection;false;CopyTo;(System.Data.DataColumn[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", ] } @@ -174,6 +176,7 @@ private class SystemDataDataRelationCollectionFlowModelCsv extends SummaryModelC row = [ "System.Data;DataRelationCollection;false;Add;(System.Data.DataRelation);;Argument[0];Argument[this].Element;value;manual", + "System.Data;DataRelationCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Data;DataRelationCollection;false;CopyTo;(System.Data.DataRelation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", "System.Data;DataRelationCollection;true;AddRange;(System.Data.DataRelation[]);;Argument[0].Element;Argument[this].Element;value;manual", ] @@ -187,6 +190,7 @@ private class SystemDataDataRawCollectionFlowModelCsv extends SummaryModelCsv { [ "System.Data;DataRowCollection;false;Add;(System.Data.DataRow);;Argument[0];Argument[this].Element;value;manual", "System.Data;DataRowCollection;false;Add;(System.Object[]);;Argument[0];Argument[this].Element;value;manual", + "System.Data;DataRowCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Data;DataRowCollection;false;CopyTo;(System.Data.DataRow[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", "System.Data;DataRowCollection;false;Find;(System.Object);;Argument[this].Element;ReturnValue;value;manual", "System.Data;DataRowCollection;false;Find;(System.Object[]);;Argument[this].Element;ReturnValue;value;manual", @@ -202,6 +206,7 @@ private class SystemDataDataTableCollectionFlowModelCsv extends SummaryModelCsv "System.Data;DataTableCollection;false;Add;(System.Data.DataTable);;Argument[0];Argument[this].Element;value;manual", "System.Data;DataTableCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual", "System.Data;DataTableCollection;false;AddRange;(System.Data.DataTable[]);;Argument[0].Element;Argument[this].Element;value;manual", + "System.Data;DataTableCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Data;DataTableCollection;false;CopyTo;(System.Data.DataTable[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", ] } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Security.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Security.qll index 02325e19383..15bfbeaef9f 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Security.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Security.qll @@ -1,6 +1,7 @@ /** Provides classes related to the namespace `System.Security`. */ import csharp +private import semmle.code.csharp.dataflow.ExternalFlow private import semmle.code.csharp.frameworks.System /** The `System.Security` namespace. */ @@ -15,3 +16,15 @@ class SystemSecurityNamespace extends Namespace { class SystemSecurityClass extends Class { SystemSecurityClass() { this.getNamespace() instanceof SystemSecurityNamespace } } + +/** Data flow for some collection like classes in `System.Security.*`. */ +private class SystemSecurityPolicyApplicationTrustCollectionFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "System.Security.Permissions;KeyContainerPermissionAccessEntryCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Security.Policy;ApplicationTrustCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Security.Policy;Evidence;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + ] + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll index 44ceb2fbae8..e26a3f73109 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll @@ -26,18 +26,6 @@ class SystemTextStringBuilderClass extends SystemTextClass { Method getAppendFormatMethod() { result = this.getAMethod("AppendFormat") } } -/** Clear content for `System.Text.StringBuilder.Clear`. */ -private class SystemTextStringBuilderClearFlow extends SummarizedCallable { - SystemTextStringBuilderClearFlow() { - this = any(SystemTextStringBuilderClass s).getAMethod("Clear") - } - - override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { - pos.isThisParameter() and - content instanceof DataFlow::ElementContent - } -} - /** Data flow for `System.Text.StringBuilder`. */ private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { @@ -120,6 +108,7 @@ private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv { "System.Text;StringBuilder;false;AppendLine;();;Argument[this];ReturnValue;value;manual", "System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[0];Argument[this].Element;value;manual", "System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[this];ReturnValue;value;manual", + "System.Text;StringBuilder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Text;StringBuilder;false;StringBuilder;(System.String);;Argument[0];Argument[this].Element;value;manual", "System.Text;StringBuilder;false;StringBuilder;(System.String,System.Int32);;Argument[0];Argument[this].Element;value;manual", "System.Text;StringBuilder;false;StringBuilder;(System.String,System.Int32,System.Int32,System.Int32);;Argument[0];Argument[this].Element;value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Concurrent.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Concurrent.qll index 34a827ee538..34022715227 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Concurrent.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Concurrent.qll @@ -44,6 +44,25 @@ private class SystemCollectionsConcurrentIProducerConsumerCollectionFlowModelCsv private class SystemCollectionsConcurrentConcurrentBagFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = - "System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual" + [ + "System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual", + "System.Collections.Concurrent;ConcurrentBag<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + ] + } +} + +/** Data flow for `System.Collections.Concurrent.ConcurrentQueue<>`. */ +private class SystemCollectionsConcurrentConcurrentQueueFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.Collections.Concurrent;ConcurrentQueue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} + +/** Data flow for `System.Collections.Concurrent.ConcurrentStack<>`. */ +private class SystemCollectionsConcurrentConcurrentStackFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.Collections.Concurrent;ConcurrentStack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" } } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll index 737dddd0ea5..9668ec4686b 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -197,6 +197,7 @@ private class SystemCollectionsGenericICollectionFlowModelCsv extends SummaryMod row = [ "System.Collections.Generic;ICollection<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual", + "System.Collections.Generic;ICollection<>;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections.Generic;ICollection<>;true;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", ] } @@ -289,6 +290,8 @@ private class SystemCollectionsGenericSortedListFlowModelCsv extends SummaryMode "System.Collections.Generic;SortedList<,>;false;SortedList;(System.Collections.Generic.IDictionary,System.Collections.Generic.IComparer);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual", "System.Collections.Generic;SortedList<,>;false;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual", "System.Collections.Generic;SortedList<,>;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual", + "System.Collections.Generic;SortedList<,>+KeyList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", + "System.Collections.Generic;SortedList<,>+ValueList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", ] } } @@ -298,6 +301,7 @@ private class SystemCollectionsGenericQueueFlowModelCsv extends SummaryModelCsv override predicate row(string row) { row = [ + "System.Collections.Generic;Queue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections.Generic;Queue<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", "System.Collections.Generic;Queue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Queue<>+Enumerator.Current];value;manual", "System.Collections.Generic;Queue<>;false;Peek;();;Argument[this].Element;ReturnValue;value;manual", @@ -310,6 +314,7 @@ private class SystemCollectionsGenericStackFlowModelCsv extends SummaryModelCsv override predicate row(string row) { row = [ + "System.Collections.Generic;Stack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections.Generic;Stack<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", "System.Collections.Generic;Stack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Stack<>+Enumerator.Current];value;manual", "System.Collections.Generic;Stack<>;false;Peek;();;Argument[this].Element;ReturnValue;value;manual", diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Immutable.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Immutable.qll index 8440db4d7e7..2264730c5df 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Immutable.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Immutable.qll @@ -6,7 +6,10 @@ private import semmle.code.csharp.dataflow.ExternalFlow private class SystemCollectionsImmutableIImmutableDictionaryFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = - "System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual" + [ + "System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual", + "System.Collections.Immutable;IImmutableDictionary<,>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", + ] } } @@ -65,6 +68,7 @@ private class SystemCollectionsImmutableIImmutableListFlowModelCsv extends Summa [ "System.Collections.Immutable;IImmutableList<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual", "System.Collections.Immutable;IImmutableList<>;true;AddRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;manual", + "System.Collections.Immutable;IImmutableList<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", ] } } @@ -124,7 +128,10 @@ private class SystemCollectionsImmutableImmutableSortedSetFlowModelCsv extends S private class SystemCollectionsImmutableIImmutableSetFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = - "System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual" + [ + "System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual", + "System.Collections.Immutable;IImmutableSet<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", + ] } } @@ -153,6 +160,7 @@ private class SystemCollectionsImmutableImmutableHashSetFlowModelCsv extends Sum [ "System.Collections.Immutable;ImmutableHashSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableHashSet<>+Enumerator.Current];value;manual", "System.Collections.Immutable;ImmutableHashSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual", + "System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", "System.Collections.Immutable;ImmutableHashSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableHashSet<>+Enumerator.Current];value;manual", ] } @@ -162,7 +170,10 @@ private class SystemCollectionsImmutableImmutableHashSetFlowModelCsv extends Sum private class SystemCollectionsImmutableImmutableQueueFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = - "System.Collections.Immutable;ImmutableQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableQueue<>+Enumerator.Current];value;manual" + [ + "System.Collections.Immutable;IImmutableQueue<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", + "System.Collections.Immutable;ImmutableQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableQueue<>+Enumerator.Current];value;manual", + ] } } @@ -170,6 +181,9 @@ private class SystemCollectionsImmutableImmutableQueueFlowModelCsv extends Summa private class SystemCollectionsImmutableImmutableStackFlowModelCsv extends SummaryModelCsv { override predicate row(string row) { row = - "System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableStack<>+Enumerator.Current];value;manual" + [ + "System.Collections.Immutable;IImmutableStack<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual", + "System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableStack<>+Enumerator.Current];value;manual", + ] } } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Specialized.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Specialized.qll index acdd2adc473..16da8fe1087 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Specialized.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Specialized.qll @@ -30,6 +30,7 @@ private class SystemCollectionsSpecializedNameValueCollectionFlowModelCsv extend row = [ "System.Collections.Specialized;NameValueCollection;false;Add;(System.Collections.Specialized.NameValueCollection);;Argument[0];Argument[this].Element;value;manual", + "System.Collections.Specialized;NameValueCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual", "System.Collections.Specialized;NameValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual", ] } @@ -70,3 +71,11 @@ private class SystemCollectionsSpecializedStringCollectionFlowModelCsv extends S ] } } + +/** Data flow for `System.Collections.Specialized.StringDictionary`. */ +private class SystemCollectionsSpecializedStringDictionaryFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.Collections.Specialized;StringDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/Common.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/Common.qll index e9c97335ce7..522e107a91b 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/Common.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/Common.qll @@ -95,3 +95,11 @@ private class SystemDataCommonDbParameterCollectionFlowModelCsv extends External ] } } + +/** Data flow for `System.Data.Common.DbBatchCommandCollection`. */ +private class SystemDataCommonDbBatchCommandCollectionFlowModelCsv extends ExternalFlow::SummaryModelCsv { + override predicate row(string row) { + row = + "System.Data.Common;DbBatchCommandCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/net/Http.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/net/Http.qll index 574945867ac..7096adee635 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/net/Http.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/net/Http.qll @@ -28,3 +28,11 @@ private class SystemNetHttpMultipartFormDataContentFlowModelCsv extends SummaryM "System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent);;Argument[0];Argument[this].Element;value;manual" } } + +/** Data flow for `System.Net.Http.Headers.HttpHeaders`. */ +private class SystemNetHttpHeadersHttpHeadersFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.Net.Http.Headers;HttpHeaders;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll index e0b2b54f59b..705896a5b0a 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll @@ -103,3 +103,11 @@ private class SystemRuntimeCompilerServicesReadOnlyCollectionBuilderFlowModelCsv ] } } + +/** Data flow for `System.Runtime.CompilerServices.ConditionalWeakTable<,>`. */ +private class SystemRuntimeCompilerServicesConditionalWeakTableFlowModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual" + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll index b194ad57d57..0770a948b09 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Remote.qll +++ b/csharp/ql/lib/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.XSSSinks as XSSSinks +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/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index a696c8bae06..4ac7d8bcac6 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -36,10 +36,9 @@ compilations( * --- | --- * 0 | --compiler * 1 | *path to compiler* - * 2 | --cil - * 3 | f1.cs - * 4 | f2.cs - * 5 | f3.cs + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs */ #keyset[id, num] compilation_args( diff --git a/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/old.dbscheme b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/old.dbscheme new file mode 100644 index 00000000000..a696c8bae06 --- /dev/null +++ b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/old.dbscheme @@ -0,0 +1,2065 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..4ac7d8bcac6 --- /dev/null +++ b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/semmlecode.csharp.dbscheme @@ -0,0 +1,2064 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/upgrade.properties b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/upgrade.properties new file mode 100644 index 00000000000..e48f6376fce --- /dev/null +++ b/csharp/ql/lib/upgrades/a696c8bae067f69ab3208e98ce35f4fdf7efb68b/upgrade.properties @@ -0,0 +1,2 @@ +description: Remove '--cil' flag from the comments. This does not make any changes to the dbscheme. +compatibility: full diff --git a/csharp/ql/src/Bad Practices/Comments/TodoComments.ql b/csharp/ql/src/Bad Practices/Comments/TodoComments.ql index bb87724678f..751c064bccf 100644 --- a/csharp/ql/src/Bad Practices/Comments/TodoComments.ql +++ b/csharp/ql/src/Bad Practices/Comments/TodoComments.ql @@ -14,4 +14,4 @@ import csharp from CommentLine c where c.getText().regexpMatch("(?s).*FIXME.*|.*TODO.*|.*(? { return true; }; + } +} \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs new file mode 100644 index 00000000000..28ba1d6f94e --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.AudienceValidator = (audiences, token, tvp) => + { + // Implement your own custom audience validation + if (PerformCustomAudienceValidation(audiences, token)) + return true; + else + return false; + }; + } +} \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp new file mode 100644 index 00000000000..8c4f8dff229 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp @@ -0,0 +1,28 @@ + + + +

    By setting critical TokenValidationParameter validation delegates to always return true, important authentication safeguards are disabled. Disabling safeguards can lead to incorrect validation of tokens from any issuer or expired tokens.

    + +
    + +

    Improve the logic of the delegate so not all code paths return true, which effectively disables that type of validation; or throw SecurityTokenInvalidAudienceException or SecurityTokenInvalidLifetimeException in failure cases when you want to fail validation and have other cases pass by returning true. +

    +
    + + +

    This example delegates AudienceValidator to a callable that always returns true.

    + + +

    To fix it, use a callable that performs a validation, and fails when appropriate.

    + + +
    + + + +
  • azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki
  • + +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql new file mode 100644 index 00000000000..57561944718 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql @@ -0,0 +1,21 @@ +/** + * @name Delegated security sensitive validations for JsonWebTokenHandler always return true, medium precision + * @description Security sensitive validations for `JsonWebTokenHandler` are being delegated to a function that seems to always return true. + * Higher precision version checks for exception throws, so less false positives are expected. + * @kind problem + * @tags security + * JsonWebTokenHandler + * manual-verification-required + * @id cs/json-webtoken-handler/delegated-security-validations-always-return-true + * @problem.severity error + * @precision high + */ + +import csharp +import DataFlow +import JsonWebTokenHandlerLib + +from TokenValidationParametersProperty p, CallableAlwaysReturnsTrueHigherPrecision e +where e = p.getAnAssignedValue() +select e, "JsonWebTokenHandler security-sensitive property $@ is being delegated to $@.", p, + p.getQualifiedName().toString(), e, "a callable that always returns \"true\"" diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-bad.cs b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-bad.cs new file mode 100644 index 00000000000..81df44fea9a --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-bad.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = false; + parameters.ValidateAudience = false; + parameters.ValidateIssuer = false; + parameters.ValidateLifetime = false; + } +} \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-good.cs b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-good.cs new file mode 100644 index 00000000000..e2f74c0653d --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-good.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = true; + parameters.ValidateAudience = true; + parameters.ValidateIssuer = true; + parameters.ValidateLifetime = true; + } +} \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qhelp b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qhelp new file mode 100644 index 00000000000..5c027ac3148 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qhelp @@ -0,0 +1,27 @@ + + + +

    Token validation checks ensure that while validating tokens, all aspects are analyzed and verified. Turning off validation can lead to security holes by allowing untrusted tokens to make it through validation.

    + +
    + +

    Set Microsoft.IdentityModel.Tokens.TokenValidationParameters properties RequireExpirationTime, ValidateAudience, ValidateIssuer, or ValidateLifetime to true. Or, remove the assignment to false because the default value is true.

    +
    + + +

    This example disabled the validation.

    + + +

    To fix it, do not disable the validations or use the default value.

    + + +
    + + + +
  • azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki
  • + +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql new file mode 100644 index 00000000000..cfc745e5314 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql @@ -0,0 +1,24 @@ +/** + * @name Security sensitive JsonWebTokenHandler validations are disabled + * @description Check if secruity sensitive token validations for `JsonWebTokenHandler` are being disabled. + * @kind problem + * @tags security + * JsonWebTokenHandler + * manual-verification-required + * @id cs/json-webtoken-handler/security-validations-disabled + * @problem.severity error + * @precision high + */ + +import csharp +import JsonWebTokenHandlerLib + +from + FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation config, + DataFlow::Node source, DataFlow::Node sink, + TokenValidationParametersPropertySensitiveValidation pw +where + config.hasFlow(source, sink) and + sink.asExpr() = pw.getAnAssignedValue() +select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw, + pw.getQualifiedName().toString(), source, "false" diff --git a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll index 0fedd38bfbd..6fca9e3b974 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll @@ -6,7 +6,7 @@ private import IRFunctionBase private import TInstruction -module SSA { +module Ssa { class MemoryLocation = boolean; predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) { @@ -17,3 +17,6 @@ module SSA { predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } } + +/** DEPRECATED: Alias for Ssa */ +deprecated module SSA = Ssa; diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index b30372a791b..5564a16f215 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -20,24 +20,24 @@ newtype TInstruction = IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation ) { - UnaliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + UnaliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) } or TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc) + UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc) } or TAliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation ) { - AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) + AliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) } or TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) { - AliasedSsa::SSA::hasChiInstruction(primaryInstruction) + AliasedSsa::Ssa::hasChiInstruction(primaryInstruction) } or TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - AliasedSsa::SSA::hasUnreachedInstruction(irFunc) + AliasedSsa::Ssa::hasUnreachedInstruction(irFunc) } /** @@ -50,7 +50,7 @@ module UnaliasedSsaInstructions { class TPhiInstruction = TUnaliasedSsaPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation ) { result = TUnaliasedSsaPhiInstruction(blockStartInstr, memoryLocation) } @@ -83,7 +83,7 @@ module AliasedSsaInstructions { class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation ) { result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll index b97981876d4..3ec2d846254 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll @@ -65,7 +65,7 @@ newtype TInstructionTag = PointerAddTag(int index) { index in [0 .. 255] } or ElementsAddressTag(int index) { index in [0 .. 255] } or ConvertTag() or - GeneratedNEQTag() or + GeneratedNeqTag() or GeneratedConstantTag() or GeneratedBranchTag() @@ -181,7 +181,7 @@ string getInstructionTagId(TInstructionTag tag) { or tag = ConvertTag() and result = "Convert" or - tag = GeneratedNEQTag() and result = "GeneratedNEQTag" + tag = GeneratedNeqTag() and result = "GeneratedNEQTag" or tag = GeneratedConstantTag() and result = "GeneratedConstantTag" or diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 08b246558b1..1bcca401565 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1710,7 +1710,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { result = this.getParent().getChildSuccessor(this) or ( - tag = GeneratedNEQTag() and + tag = GeneratedNeqTag() and kind instanceof GotoEdge and if this.hasVar() then result = this.getInstruction(GeneratedBranchTag()) @@ -1733,7 +1733,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { kind instanceof GotoEdge and if this.hasVar() then result = this.getPatternVarDecl().getFirstInstruction() - else result = this.getInstruction(GeneratedNEQTag()) + else result = this.getInstruction(GeneratedNeqTag()) } override Instruction getChildSuccessor(TranslatedElement child) { @@ -1742,7 +1742,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { or this.hasVar() and child = this.getPatternVarDecl() and - result = this.getInstruction(GeneratedNEQTag()) + result = this.getInstruction(GeneratedNeqTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { @@ -1755,7 +1755,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { opcode instanceof Opcode::CheckedConvertOrNull and resultType = getTypeForPRValue(expr.getPattern().getType()) or - tag = GeneratedNEQTag() and + tag = GeneratedNeqTag() and opcode instanceof Opcode::CompareNE and resultType = getTypeForPRValue(expr.getType()) or @@ -1775,7 +1775,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { result = "0" } - override Instruction getResult() { result = this.getInstruction(GeneratedNEQTag()) } + override Instruction getResult() { result = this.getInstruction(GeneratedNeqTag()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = ConvertTag() and @@ -1792,7 +1792,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { result = this.getPatternVarDecl().getTargetAddress() ) or - tag = GeneratedNEQTag() and + tag = GeneratedNeqTag() and ( operandTag instanceof LeftOperandTag and result = this.getInstruction(ConvertTag()) @@ -1804,7 +1804,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { this.hasVar() and tag = GeneratedBranchTag() and operandTag instanceof ConditionOperandTag and - result = this.getInstruction(GeneratedNEQTag()) + result = this.getInstruction(GeneratedNeqTag()) } private TranslatedExpr getIsExpr() { result = getTranslatedExpr(expr.getExpr()) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 1c75529be00..873a3c635f8 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ -private import SSAConstruction as SSA -import SSA::SsaConsistency +private import SSAConstruction as Ssa +import Ssa::SsaConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 901735069c0..21c03e176a5 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1135,7 +1135,7 @@ deprecated module SSAConsistency = SsaConsistency; * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures * that all of SSA construction will be evaluated in the same stage. */ -module SSA { +module Ssa { class MemoryLocation = Alias::MemoryLocation; predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; @@ -1144,3 +1144,6 @@ module SSA { predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } + +/** DEPRECATED: Alias for Ssa */ +deprecated module SSA = Ssa; diff --git a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql index 6276f9793dc..b9e0cc23987 100644 --- a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql @@ -4,10 +4,10 @@ * @id csharp/utils/model-generator/discarded-summary-models */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string flow +from DataFlowTargetApi api, string flow where flow = captureFlow(api) and hasSummary(api, false) select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql index 09202f423ea..0e26d3eee7f 100644 --- a/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql @@ -6,10 +6,12 @@ * @tags model-generator */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string noflow -where noflow = captureNoFlow(api) and not hasSummary(api, false) +from DataFlowTargetApi api, string noflow +where + noflow = captureNoFlow(api) and + not hasSummary(api, false) select noflow order by noflow diff --git a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql index 03eeeeda273..ea249016427 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string sink +from DataFlowTargetApi api, string sink where sink = captureSink(api) select sink order by sink diff --git a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql index f60682b2b6d..72ce31d4b61 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string source +from DataFlowTargetApi api, string source where source = captureSource(api) select source order by source diff --git a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql index f6c91335428..f308c57c89d 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql @@ -6,10 +6,10 @@ * @tags model-generator */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string flow +from DataFlowTargetApi api, string flow where flow = captureFlow(api) and not hasSummary(api, false) select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql new file mode 100644 index 00000000000..e3dcc9dc2f6 --- /dev/null +++ b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql @@ -0,0 +1,14 @@ +/** + * @name Capture typed based summary models. + * @description Finds applicable summary models to be used by other queries. + * @kind diagnostic + * @id cs/utils/model-generator/summary-models-typed-based + * @tags model-generator + */ + +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureTypeBasedSummaryModels + +from TypeBasedFlowTargetApi api, string flow +where flow = captureFlow(api) +select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll index 2547b058e18..82c6fbd1bbb 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -5,7 +5,9 @@ private import CaptureModelsSpecific -class TargetApi = TargetApiSpecific; +class DataFlowTargetApi extends TargetApiSpecific { + DataFlowTargetApi() { isRelevantForDataFlowModels(this) } +} /** * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. @@ -40,7 +42,7 @@ private predicate isRelevantContent(DataFlow::Content c) { * Gets the summary model for `api` with `input`, `output` and `kind`. */ bindingset[input, output, kind] -private string asSummaryModel(TargetApi api, string input, string output, string kind) { +private string asSummaryModel(TargetApiSpecific api, string input, string output, string kind) { result = asPartialModel(api) + input + ";" // + output + ";" // @@ -48,13 +50,15 @@ private string asSummaryModel(TargetApi api, string input, string output, string + "generated" } -string asNegativeSummaryModel(TargetApi api) { result = asPartialNegativeModel(api) + "generated" } +string asNegativeSummaryModel(TargetApiSpecific api) { + result = asPartialNegativeModel(api) + "generated" +} /** * Gets the value summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asValueModel(TargetApi api, string input, string output) { +string asValueModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "value") } @@ -62,7 +66,7 @@ private string asValueModel(TargetApi api, string input, string output) { * Gets the taint summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asTaintModel(TargetApi api, string input, string output) { +private string asTaintModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "taint") } @@ -70,7 +74,7 @@ private string asTaintModel(TargetApi api, string input, string output) { * Gets the sink model for `api` with `input` and `kind`. */ bindingset[input, kind] -private string asSinkModel(TargetApi api, string input, string kind) { +private string asSinkModel(TargetApiSpecific api, string input, string kind) { result = asPartialModel(api) + input + ";" // + kind + ";" // @@ -81,7 +85,7 @@ private string asSinkModel(TargetApi api, string input, string kind) { * Gets the source model for `api` with `output` and `kind`. */ bindingset[output, kind] -private string asSourceModel(TargetApi api, string output, string kind) { +private string asSourceModel(TargetApiSpecific api, string output, string kind) { result = asPartialModel(api) + output + ";" // + kind + ";" // @@ -91,7 +95,7 @@ private string asSourceModel(TargetApi api, string output, string kind) { /** * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). */ -string captureQualifierFlow(TargetApi api) { +string captureQualifierFlow(TargetApiSpecific api) { exists(DataFlowImplCommon::ReturnNodeExt ret | api = returnNodeEnclosingCallable(ret) and isOwnInstanceAccessNode(ret) @@ -140,7 +144,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof TargetApi and + source.getEnclosingCallable() instanceof DataFlowTargetApi and state.(TaintRead).getStep() = 0 } @@ -184,7 +188,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { /** * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. */ -string captureThroughFlow(TargetApi api) { +string captureThroughFlow(DataFlowTargetApi api) { exists( ThroughFlowConfig config, DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input, string output @@ -211,7 +215,7 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) } override predicate isSink(DataFlow::Node sink) { - exists(TargetApi c | + exists(DataFlowTargetApi c | sink instanceof DataFlowImplCommon::ReturnNodeExt and sink.getEnclosingCallable() = c ) @@ -229,11 +233,12 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { /** * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. */ -string captureSource(TargetApi api) { +string captureSource(DataFlowTargetApi api) { exists(DataFlow::Node source, DataFlow::Node sink, FromSourceConfiguration config, string kind | config.hasFlow(source, sink) and ExternalFlow::sourceNode(source, kind) and api = sink.getEnclosingCallable() and + isRelevantSourceKind(kind) and result = asSourceModel(api, returnNodeAsOutput(sink), kind) ) } @@ -258,7 +263,7 @@ private class PropagateToSinkConfiguration extends PropagateToSinkConfigurationS /** * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. */ -string captureSink(TargetApi api) { +string captureSink(DataFlowTargetApi api) { exists(DataFlow::Node src, DataFlow::Node sink, PropagateToSinkConfiguration config, string kind | config.hasFlow(src, sink) and ExternalFlow::sinkNode(sink, kind) and diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll index f95684370ce..3b0a33336c0 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll @@ -36,10 +36,21 @@ private predicate isRelevantForModels(CS::Callable api) { api.getDeclaringType().getNamespace().getQualifiedName() != "" and not api instanceof CS::ConversionOperator and not api instanceof Util::MainMethod and - not isHigherOrder(api) and not api instanceof CS::Destructor } +/** + * Holds if it is relevant to generate models for `api` based on data flow analysis. + */ +predicate isRelevantForDataFlowModels(CS::Callable api) { + isRelevantForModels(api) and not isHigherOrder(api) +} + +/** + * Holds if it is relevant to generate models for `api` based on its type. + */ +predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1; + /** * A class of callables that are relevant generating summary, source and sinks models for. * @@ -49,8 +60,7 @@ private predicate isRelevantForModels(CS::Callable api) { class TargetApiSpecific extends DotNet::Callable { TargetApiSpecific() { this.fromSource() and - this.isUnboundDeclaration() and - isRelevantForModels(this) + this.isUnboundDeclaration() } } @@ -58,6 +68,31 @@ predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1; predicate asPartialNegativeModel = DataFlowPrivate::Csv::asPartialNegativeModel/1; +/** + * Holds if `t` is a type that is generally used for bulk data in collection types. + * Eg. char[] is roughly equivalent to string and thus a highly + * relevant type for model generation. + */ +private predicate isPrimitiveTypeUsedForBulkData(CS::Type t) { + t instanceof CS::ByteType or + t instanceof CS::CharType +} + +/** + * Holds if the collection type `ct` is irrelevant for model generation. + * Collection types where the type of the elements are + * (1) unknown - are considered relevant. + * (2) known - at least one the child types should be relevant (a non-simple type + * or a type used for bulk data) + */ +private predicate irrelevantCollectionType(CS::Type ct) { + Collections::isCollectionType(ct) and + forex(CS::Type child | child = ct.getAChild() | + child instanceof CS::SimpleType and + not isPrimitiveTypeUsedForBulkData(child) + ) +} + /** * Holds for type `t` for fields that are relevant as an intermediate * read or write step in the data flow analysis. @@ -66,7 +101,8 @@ predicate asPartialNegativeModel = DataFlowPrivate::Csv::asPartialNegativeModel/ */ predicate isRelevantType(CS::Type t) { not t instanceof CS::SimpleType and - not t instanceof CS::Enum + not t instanceof CS::Enum and + not irrelevantCollectionType(t) } /** @@ -74,7 +110,7 @@ predicate isRelevantType(CS::Type t) { */ string qualifierString() { result = "Argument[this]" } -private string parameterAccess(CS::Parameter p) { +string parameterAccess(CS::Parameter p) { if Collections::isCollectionType(p.getType()) then result = "Argument[" + p.getPosition() + "].Element" else result = "Argument[" + p.getPosition() + "]" @@ -167,3 +203,9 @@ string asInputArgument(DataFlow::Node source) { */ bindingset[kind] predicate isRelevantSinkKind(string kind) { any() } + +/** + * Holds if `kind` is a relevant source kind for creating source models. + */ +bindingset[kind] +predicate isRelevantSourceKind(string kind) { not kind = "file" } diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll b/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll index 65a5181ee89..e06ea1a609a 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll @@ -75,7 +75,7 @@ private import CaptureModels * Captured Model: * ```Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint``` */ -string captureFlow(TargetApi api) { +string captureFlow(DataFlowTargetApi api) { result = captureQualifierFlow(api) or result = captureThroughFlow(api) } @@ -84,7 +84,7 @@ string captureFlow(TargetApi api) { * Gets the negative summary for `api`, if any. * A negative summary is generated, if there does not exist any positive flow. */ -string captureNoFlow(TargetApi api) { +string captureNoFlow(DataFlowTargetApi api) { not exists(captureFlow(api)) and result = asNegativeSummaryModel(api) } diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll new file mode 100644 index 00000000000..02f00986c3c --- /dev/null +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll @@ -0,0 +1,224 @@ +private import csharp +private import dotnet +private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate +private import semmle.code.csharp.frameworks.system.linq.Expressions +private import CaptureModelsSpecific as Specific +private import CaptureModels + +/** + * Holds if `t` is a subtype (reflexive/transitive) of `IEnumerable`, where `T` = `tp`. + */ +private predicate genericCollectionType(ValueOrRefType t, TypeParameter tp) { + exists(ConstructedGeneric t2 | + t2 = t.getABaseType*() and + t2.getUnboundDeclaration() instanceof + GenericCollections::SystemCollectionsGenericIEnumerableTInterface and + tp = t2.getATypeArgument() + ) +} + +/** + * Holds if `tp` is a type parameter of the immediate type declaring `callable`. + */ +private predicate classTypeParameter(DotNet::Callable callable, TypeParameter tp) { + callable.getDeclaringType().(UnboundGeneric).getATypeParameter() = tp +} + +/** + * Holds if `tp` is type parameter of `callable` or the type declaring `callable`. + */ +private predicate localTypeParameter(DotNet::Callable callable, TypeParameter tp) { + classTypeParameter(callable, tp) or + callable.(UnboundGeneric).getATypeParameter() = tp +} + +/** + * Holds if `callable` has a parameter of type `tp` + * or collection parameterized over type `tp`. + */ +private predicate parameter(DotNet::Callable callable, string input, TypeParameter tp) { + exists(Parameter p | + input = Specific::parameterAccess(p) and + p = callable.getAParameter() and + ( + // Parameter of type tp + p.getType() = tp + or + // Parameter is a collection of type tp + genericCollectionType(p.getType(), tp) + ) + ) +} + +/** + * Gets the string representation of a synthetic field corresponding to `tp`. + */ +private string getSyntheticField(TypeParameter tp) { + result = ".SyntheticField[ArgType" + tp.getIndex() + "]" +} + +/** + * Gets a models as data string representation of, how a value of type `tp` + * can be read or stored implicitly in relation to `callable`. + */ +private string implicit(DotNet::Callable callable, TypeParameter tp) { + classTypeParameter(callable, tp) and + exists(string access | + if genericCollectionType(callable.getDeclaringType(), tp) + then access = ".Element" + else access = getSyntheticField(tp) + | + result = Specific::qualifierString() + access + ) +} + +/** + * Holds if `callable` has a delegate parameter `dt` at parameter position `position`. + */ +private predicate delegate(DotNet::Callable callable, DelegateType dt, int position) { + exists(Parameter p | + p = callable.getAParameter() and + dt = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() and + position = p.getPosition() + ) +} + +/** + * Gets models as data input/output access relative to the type parameter `tp` in the + * type `t` in the scope of `callable`. + * + * Note: This predicate has to be inlined as `callable` is not related to `return` or `tp` + * in every disjunction. + */ +bindingset[callable] +private string getAccess(DotNet::Callable callable, Type return, TypeParameter tp) { + return = tp and result = "" + or + genericCollectionType(return, tp) and result = ".Element" + or + not genericCollectionType(return, tp) and + ( + return.(ConstructedGeneric).getATypeArgument() = tp + or + callable.getDeclaringType() = return and return.(UnboundGeneric).getATypeParameter() = tp + ) and + result = getSyntheticField(tp) +} + +/** + * Holds if `input` is a models as data string representation of, how a value of type `tp` + * (or a generic parameterized over `tp`) can be generated by a delegate parameter of `callable`. + */ +private predicate delegateSource(DotNet::Callable callable, string input, TypeParameter tp) { + exists(DelegateType dt, int position, Type return, string access | + delegate(callable, dt, position) and + return = dt.getReturnType() and + access = getAccess(callable, return, tp) and + input = "Argument[" + position + "].ReturnValue" + access + ) +} + +/** + * Holds if `input` is a models as data string representation of, how a + * value of type `tp` (or a generic parameterized over `tp`) + * can be provided as input to `callable`. + * This includes + * (1) The implicit synthetic field(s) of the declaring type of `callable`. + * (2) The parameters of `callable`. + * (3) Any delegate parameters of `callable`. + */ +private predicate input(DotNet::Callable callable, string input, TypeParameter tp) { + input = implicit(callable, tp) + or + parameter(callable, input, tp) + or + delegateSource(callable, input, tp) +} + +/** + * Holds if `callable` returns a value of type `tp` (or a generic parameterized over `tp`) and `output` + * is a models as data string representation of, how data is routed to the return. + */ +private predicate returns(DotNet::Callable callable, TypeParameter tp, string output) { + exists(Type return, string access | return = callable.getReturnType() | + access = getAccess(callable, return, tp) and + output = "ReturnValue" + access + ) +} + +/** + * Holds if `callable` has a delegate parameter that accepts a value of type `tp` + * and `output` is the models as data string representation of, how data is routed to + * the delegate parameter. + */ +private predicate delegateSink(DotNet::Callable callable, TypeParameter tp, string output) { + exists(DelegateType dt, int position, Parameter p | + delegate(callable, dt, position) and + p = dt.getAParameter() and + p.getType() = tp and + output = "Argument[" + position + "]" + ".Parameter[" + p.getPosition() + "]" + ) +} + +/** + * Holds if `output` is a models as data string representation of, how values of type `tp` + * (or generics parameterized over `tp`) can be routed. + * This includes + * (1) The implicit synthetic field(s) of the declaring type of `callable`. + * (2) The return of `callable`. + * (3) Any delegate parameters of `callable`. + */ +private predicate output(DotNet::Callable callable, TypeParameter tp, string output) { + output = implicit(callable, tp) + or + returns(callable, tp, output) + or + delegateSink(callable, tp, output) +} + +/** + * A class of callables that are relevant generating summaries for based + * on the Theorems for Free approach. + */ +class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific { + TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) } + + /** + * Gets the string representation of all type based summaries for `this` + * inspired by the Theorems for Free approach. + * + * Examples could be (see C# psuedo code below) + * (1) `Get` returns a value of type `T`. We assume that the returned + * value was fetched from a (synthetic) field. + * (2) `Set` consumes a value of type `T`. We assume that the value is stored in + * a (synthetic) field. + * (3) `Apply` is assumed to apply the provided function to a value stored in + * a (synthetic) field and return the result. + * (4) `Apply` is assumed to apply the provided function to provided value + * and return the result. + * ```csharp + * public class MyGeneric { + * public void Set(T x) { ... } + * public T Get() { ... } + * public S Apply(Func f) { ... } + * public S2 Apply(S1 x, Func f) { ... } + * } + * ``` + */ + string getSummaries() { + exists(TypeParameter tp, string input, string output | + localTypeParameter(this, tp) and + input(this, input, tp) and + output(this, tp, output) and + input != output + | + result = asValueModel(this, input, output) + ) + } +} + +/** + * Returns the Theorems for Free inspired typed based summaries for `api`. + */ +string captureFlow(TypeBasedFlowTargetApi api) { result = api.getSummaries() } diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected new file mode 100644 index 00000000000..dc224c9586e --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected @@ -0,0 +1,7 @@ +| delegation-test.cs:101:63:101:186 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:54:34:54:50 | LifetimeValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.LifetimeValidator | delegation-test.cs:101:63:101:186 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:102:63:102:178 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:102:63:102:178 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:115:63:115:190 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:115:63:115:190 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:116:63:116:180 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:116:63:116:180 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:117:63:117:217 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:117:63:117:217 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:118:63:118:248 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:118:63:118:248 | (...) => ... | a callable that always returns "true" | +| delegation-test.cs:119:63:119:177 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to $@. | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | delegation-test.cs:119:63:119:177 | (...) => ... | a callable that always returns "true" | diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref new file mode 100644 index 00000000000..527ea925973 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref @@ -0,0 +1 @@ +experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegation-test.cs b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegation-test.cs new file mode 100644 index 00000000000..01af41c4b0c --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/delegation-test.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.JsonWebTokens; + +namespace JsonWebTokenHandlerTest +{ + public class JsonWebTokenHandler_00 + { + public static object ThrowIfNull(string name, object value) + { + if (value == null) + { + throw new System.ArgumentNullException(name); + } + return value; + } + + private static bool MayThrowException(SecurityToken token) + { + if (token.Id == null) + { + throw new Exception("foobar"); + } + return true; + } + + private static void DoesNotThrowException(SecurityToken token) + { + int x = 0; + } + + private static bool ValidateLifetime_FP01( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token == null) + { + throw new System.ArgumentNullException("token"); + } + + MayThrowException(token); + + return true; + } + + private static bool ValidateLifetime_P01( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token == null) + { + throw new System.ArgumentNullException("token"); + } + + DoesNotThrowException(token); + + return true; + } + + + internal static bool ValidateLifetimeAlwaysTrue( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token is null) + { + return true; + } + return true; + } + + internal static bool ValidateLifetime( + string token, + TokenValidationParameters validationParameters) + { + if (token is null) + { + return false; + } + return true; + } + + public void TestCase01() + { + TokenValidationParameters tokenValidationParamsBaseline = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = true, + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + RequireExpirationTime = true, + ValidateTokenReplay = true, + RequireSignedTokens = true, + RequireAudience = true, + SaveSigninToken = true + }; + + tokenValidationParamsBaseline.LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => ValidateLifetimeAlwaysTrue(securityToken, validationParameters); // BUG delegated-security-validations-always-return-true + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => true; // BUG delegated-security-validations-always-return-true + tokenValidationParamsBaseline.TokenReplayValidator = (DateTime? expirationTime, string securityToken, TokenValidationParameters validationParameters) => // GOOD + { + if (securityToken is null) + { + return false; + } + return true; + }; + + tokenValidationParamsBaseline.LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => ValidateLifetime02(securityToken, validationParameters); // GOOD + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => {return securityToken is null?false:true; }; // GOOD + + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return true; }; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => !false ; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return securityToken is null?true:true; }; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return ValidateLifetimeAlwaysTrue(securityToken, validationParameters);}; //BUG + tokenValidationParamsBaseline.AudienceValidator = (audiences, securityToken, validationParameters) => ValidateLifetimeAlwaysTrue(securityToken, validationParameters); //BUG + + } + + internal static bool ValidateLifetime02( + SecurityToken token, + TokenValidationParameters validationParameters) + { + return token is null?false:true; + } + + internal static bool ValidateLifetimeAlwaysTrue02( + SecurityToken token, + TokenValidationParameters validationParameters) + { + return !false; + } + } +} \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-test.cs b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-test.cs new file mode 100644 index 00000000000..505aba41416 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled-test.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Microsoft.IdentityModel.Tokens; + +namespace JsonWebTokenHandlerTest +{ + public class JsonWebTokenHandler_class01 + { + public void TestCase01() + { + TokenValidationParameters tokenValidationParamsBaseline = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = true, + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + RequireExpirationTime = true, + ValidateTokenReplay = true, + RequireSignedTokens = true, + RequireAudience = true, + SaveSigninToken = true + }; + + TokenValidationParameters tokenValidationParams = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = false, + ValidateIssuerSigningKey = false, + ValidateIssuer = false, // BUG + ValidateAudience = false, // BUG + ValidateLifetime = false, // BUG + RequireExpirationTime = false, // BUG + ValidateTokenReplay = false, + RequireSignedTokens = false, + RequireAudience = false, // BUG + SaveSigninToken = false + }; + } + + } +} \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.expected b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.expected new file mode 100644 index 00000000000..4a0a5afce6f --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.expected @@ -0,0 +1,5 @@ +| security-validation-disabled-test.cs:31:34:31:38 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:43:21:43:34 | ValidateIssuer | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateIssuer | security-validation-disabled-test.cs:31:34:31:38 | false | false | +| security-validation-disabled-test.cs:32:36:32:40 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:44:21:44:36 | ValidateAudience | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateAudience | security-validation-disabled-test.cs:32:36:32:40 | false | false | +| security-validation-disabled-test.cs:33:36:33:40 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:45:21:45:36 | ValidateLifetime | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateLifetime | security-validation-disabled-test.cs:33:36:33:40 | false | false | +| security-validation-disabled-test.cs:34:41:34:45 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:51:21:51:41 | RequireExpirationTime | Microsoft.IdentityModel.Tokens.TokenValidationParameters.RequireExpirationTime | security-validation-disabled-test.cs:34:41:34:45 | false | false | +| security-validation-disabled-test.cs:37:35:37:39 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:50:21:50:35 | RequireAudience | Microsoft.IdentityModel.Tokens.TokenValidationParameters.RequireAudience | security-validation-disabled-test.cs:37:35:37:39 | false | false | diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qlref b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qlref new file mode 100644 index 00000000000..ee07957fa06 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.qlref @@ -0,0 +1 @@ +experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/stubs.cs b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/stubs.cs new file mode 100644 index 00000000000..1d0e0de00a3 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/JsonWebTokenHandler/stubs.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel +{ + +} + +namespace Microsoft.IdentityModel.Tokens +{ + public abstract class SecurityToken + { + protected SecurityToken() { } + public string Id { get; } + public string Issuer { get; } + public DateTime ValidFrom { get; } + public DateTime ValidTo { get; } + } + + public abstract class TokenHandler + { + public static readonly int DefaultTokenLifetimeInMinutes; + + protected TokenHandler() { } + + public virtual int MaximumTokenSizeInBytes { get; set; } + public bool SetDefaultTimesOnTokenCreation { get; set; } + public int TokenLifetimeInMinutes { get; set; } + } + + public delegate bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters); + public delegate bool AudienceValidator(IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters); + public delegate bool TokenReplayValidator(DateTime? expirationTime, string securityToken, TokenValidationParameters validationParameters); + public delegate string IssuerValidator(string issuer, SecurityToken securityToken, TokenValidationParameters validationParameters); + + public class TokenValidationParameters + { + public const int DefaultMaximumTokenSizeInBytes = 256000; + public static readonly string DefaultAuthenticationType; + public static readonly TimeSpan DefaultClockSkew; + public TimeSpan ClockSkew { get; set; } + public bool SaveSigninToken { get; set; } + public bool ValidateIssuer { get; set; } + public bool ValidateAudience { get; set; } + public bool ValidateLifetime { get; set; } + public bool ValidateIssuerSigningKey { get; set; } + public bool ValidateTokenReplay { get; set; } + public bool ValidateActor { get; set; } + public bool RequireSignedTokens { get; set; } + public bool RequireAudience { get; set; } + public bool RequireExpirationTime { get; set; } + + // Delegation + public LifetimeValidator LifetimeValidator { get; set; } + public AudienceValidator AudienceValidator { get; set; } + public TokenReplayValidator TokenReplayValidator { get; set; } + public IssuerValidator IssuerValidator { get; set; } + + /* + public TokenValidationParameters() { } + public SignatureValidator SignatureValidator { get; set; } + public SecurityKey TokenDecryptionKey { get; set; } + public TokenDecryptionKeyResolver TokenDecryptionKeyResolver { get; set; } + public IEnumerable TokenDecryptionKeys { get; set; } + public TokenReader TokenReader { get; set; } + public ITokenReplayCache TokenReplayCache { get; set; } + public Func RoleClaimTypeRetriever { get; set; } + public string ValidAudience { get; set; } + public IEnumerable ValidAudiences { get; set; } + public string ValidIssuer { get; set; } + public IEnumerable ValidIssuers { get; set; } + public TokenValidationParameters ActorValidationParameters { get; set; } + public AudienceValidator AudienceValidator { get; set; } + public string AuthenticationType { get; set; } + public CryptoProviderFactory CryptoProviderFactory { get; set; } + public IssuerSigningKeyValidator IssuerSigningKeyValidator { get; set; } + public SecurityKey IssuerSigningKey { get; set; } + public IEnumerable IssuerSigningKeys { get; set; } + public IssuerValidator IssuerValidator { get; set; } + public string NameClaimType { get; set; } + public string RoleClaimType { get; set; } + public Func NameClaimTypeRetriever { get; set; } + public IDictionary PropertyBag { get; set; } + public IssuerSigningKeyResolver IssuerSigningKeyResolver { get; set; } + public IEnumerable ValidTypes { get; set; } + public virtual TokenValidationParameters Clone(); + public virtual string CreateClaimsIdentity(SecurityToken securityToken, string issuer); + */ + } + +} + +namespace Microsoft.IdentityModel.JsonWebTokens +{ + public class JsonWebTokenHandler : Microsoft.IdentityModel.Tokens.TokenHandler + { + public virtual TokenValidationResult ValidateToken(string token, Microsoft.IdentityModel.Tokens.TokenValidationParameters validationParameters) + { + return new TokenValidationResult() { IsValid = true, Exception = null, Issuer = "test" }; + } + } + + public class TokenValidationResult + { + public TokenValidationResult() { } + + public Exception Exception { get; set; } + public string Issuer { get; set; } + public bool IsValid { get; set; } + public Microsoft.IdentityModel.Tokens.SecurityToken SecurityToken { get; set; } + public string ClaimsIdentity { get; set; } + } + + +} diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs index 26b6936543f..7f307e390ea 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs @@ -112,6 +112,14 @@ namespace My.Qltest Sink(f.MyProp); } + void M17() + { + var a = new object[] { new object() }; + var b = Reverse(a); + Sink(b); // No flow + Sink(b[0]); // Flow + } + object StepArgRes(object x) { return null; } void StepArgArg(object @in, object @out) { } @@ -147,6 +155,8 @@ namespace My.Qltest static void Parse(string s, out int i) => throw null; + static object[] Reverse(object[] elements) => throw null; + static void Sink(object o) { } } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected index cf22a1ee1b1..1cddde807fb 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected @@ -56,14 +56,19 @@ edges | ExternalFlow.cs:111:13:111:13 | [post] access to local variable f [field MyField] : Object | ExternalFlow.cs:112:18:112:18 | access to local variable f [field MyField] : Object | | ExternalFlow.cs:111:24:111:35 | object creation of type Object : Object | ExternalFlow.cs:111:13:111:13 | [post] access to local variable f [field MyField] : Object | | ExternalFlow.cs:112:18:112:18 | access to local variable f [field MyField] : Object | ExternalFlow.cs:112:18:112:25 | access to property MyProp | -| ExternalFlow.cs:177:21:177:32 | object creation of type Object : Object | ExternalFlow.cs:178:32:178:32 | access to local variable o : Object | -| ExternalFlow.cs:178:32:178:32 | access to local variable o : Object | ExternalFlow.cs:178:18:178:33 | call to method GeneratedFlow | -| ExternalFlow.cs:183:22:183:33 | object creation of type Object : Object | ExternalFlow.cs:184:36:184:37 | access to local variable o1 : Object | -| ExternalFlow.cs:184:36:184:37 | access to local variable o1 : Object | ExternalFlow.cs:184:18:184:44 | call to method GeneratedFlowArgs | -| ExternalFlow.cs:186:22:186:33 | object creation of type Object : Object | ExternalFlow.cs:187:42:187:43 | access to local variable o2 : Object | -| ExternalFlow.cs:187:42:187:43 | access to local variable o2 : Object | ExternalFlow.cs:187:18:187:44 | call to method GeneratedFlowArgs | -| ExternalFlow.cs:195:22:195:33 | object creation of type Object : Object | ExternalFlow.cs:196:38:196:39 | access to local variable o2 : Object | -| ExternalFlow.cs:196:38:196:39 | access to local variable o2 : Object | ExternalFlow.cs:196:18:196:40 | call to method MixedFlowArgs | +| ExternalFlow.cs:117:34:117:49 | { ..., ... } [element] : Object | ExternalFlow.cs:118:29:118:29 | access to local variable a [element] : Object | +| ExternalFlow.cs:117:36:117:47 | object creation of type Object : Object | ExternalFlow.cs:117:34:117:49 | { ..., ... } [element] : Object | +| ExternalFlow.cs:118:21:118:30 | call to method Reverse [element] : Object | ExternalFlow.cs:120:18:120:18 | access to local variable b [element] : Object | +| ExternalFlow.cs:118:29:118:29 | access to local variable a [element] : Object | ExternalFlow.cs:118:21:118:30 | call to method Reverse [element] : Object | +| ExternalFlow.cs:120:18:120:18 | access to local variable b [element] : Object | ExternalFlow.cs:120:18:120:21 | access to array element | +| ExternalFlow.cs:187:21:187:32 | object creation of type Object : Object | ExternalFlow.cs:188:32:188:32 | access to local variable o : Object | +| ExternalFlow.cs:188:32:188:32 | access to local variable o : Object | ExternalFlow.cs:188:18:188:33 | call to method GeneratedFlow | +| ExternalFlow.cs:193:22:193:33 | object creation of type Object : Object | ExternalFlow.cs:194:36:194:37 | access to local variable o1 : Object | +| ExternalFlow.cs:194:36:194:37 | access to local variable o1 : Object | ExternalFlow.cs:194:18:194:44 | call to method GeneratedFlowArgs | +| ExternalFlow.cs:196:22:196:33 | object creation of type Object : Object | ExternalFlow.cs:197:42:197:43 | access to local variable o2 : Object | +| ExternalFlow.cs:197:42:197:43 | access to local variable o2 : Object | ExternalFlow.cs:197:18:197:44 | call to method GeneratedFlowArgs | +| ExternalFlow.cs:205:22:205:33 | object creation of type Object : Object | ExternalFlow.cs:206:38:206:39 | access to local variable o2 : Object | +| ExternalFlow.cs:206:38:206:39 | access to local variable o2 : Object | ExternalFlow.cs:206:18:206:40 | call to method MixedFlowArgs | nodes | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | semmle.label | call to method StepArgRes | @@ -138,18 +143,24 @@ nodes | ExternalFlow.cs:111:24:111:35 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:112:18:112:18 | access to local variable f [field MyField] : Object | semmle.label | access to local variable f [field MyField] : Object | | ExternalFlow.cs:112:18:112:25 | access to property MyProp | semmle.label | access to property MyProp | -| ExternalFlow.cs:177:21:177:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:178:18:178:33 | call to method GeneratedFlow | semmle.label | call to method GeneratedFlow | -| ExternalFlow.cs:178:32:178:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| ExternalFlow.cs:183:22:183:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:184:18:184:44 | call to method GeneratedFlowArgs | semmle.label | call to method GeneratedFlowArgs | -| ExternalFlow.cs:184:36:184:37 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | -| ExternalFlow.cs:186:22:186:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:187:18:187:44 | call to method GeneratedFlowArgs | semmle.label | call to method GeneratedFlowArgs | -| ExternalFlow.cs:187:42:187:43 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | -| ExternalFlow.cs:195:22:195:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| ExternalFlow.cs:196:18:196:40 | call to method MixedFlowArgs | semmle.label | call to method MixedFlowArgs | -| ExternalFlow.cs:196:38:196:39 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:117:34:117:49 | { ..., ... } [element] : Object | semmle.label | { ..., ... } [element] : Object | +| ExternalFlow.cs:117:36:117:47 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:118:21:118:30 | call to method Reverse [element] : Object | semmle.label | call to method Reverse [element] : Object | +| ExternalFlow.cs:118:29:118:29 | access to local variable a [element] : Object | semmle.label | access to local variable a [element] : Object | +| ExternalFlow.cs:120:18:120:18 | access to local variable b [element] : Object | semmle.label | access to local variable b [element] : Object | +| ExternalFlow.cs:120:18:120:21 | access to array element | semmle.label | access to array element | +| ExternalFlow.cs:187:21:187:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:188:18:188:33 | call to method GeneratedFlow | semmle.label | call to method GeneratedFlow | +| ExternalFlow.cs:188:32:188:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| ExternalFlow.cs:193:22:193:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:194:18:194:44 | call to method GeneratedFlowArgs | semmle.label | call to method GeneratedFlowArgs | +| ExternalFlow.cs:194:36:194:37 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:196:22:196:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:197:18:197:44 | call to method GeneratedFlowArgs | semmle.label | call to method GeneratedFlowArgs | +| ExternalFlow.cs:197:42:197:43 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:205:22:205:33 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:206:18:206:40 | call to method MixedFlowArgs | semmle.label | call to method MixedFlowArgs | +| ExternalFlow.cs:206:38:206:39 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | subpaths invalidModelRow #select @@ -172,7 +183,8 @@ invalidModelRow | ExternalFlow.cs:102:22:102:22 | access to parameter d | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:104:18:104:25 | access to field Field | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:104:18:104:25 | access to field Field | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:112:18:112:25 | access to property MyProp | ExternalFlow.cs:111:24:111:35 | object creation of type Object : Object | ExternalFlow.cs:112:18:112:25 | access to property MyProp | $@ | ExternalFlow.cs:111:24:111:35 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:178:18:178:33 | call to method GeneratedFlow | ExternalFlow.cs:177:21:177:32 | object creation of type Object : Object | ExternalFlow.cs:178:18:178:33 | call to method GeneratedFlow | $@ | ExternalFlow.cs:177:21:177:32 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:184:18:184:44 | call to method GeneratedFlowArgs | ExternalFlow.cs:183:22:183:33 | object creation of type Object : Object | ExternalFlow.cs:184:18:184:44 | call to method GeneratedFlowArgs | $@ | ExternalFlow.cs:183:22:183:33 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:187:18:187:44 | call to method GeneratedFlowArgs | ExternalFlow.cs:186:22:186:33 | object creation of type Object : Object | ExternalFlow.cs:187:18:187:44 | call to method GeneratedFlowArgs | $@ | ExternalFlow.cs:186:22:186:33 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:196:18:196:40 | call to method MixedFlowArgs | ExternalFlow.cs:195:22:195:33 | object creation of type Object : Object | ExternalFlow.cs:196:18:196:40 | call to method MixedFlowArgs | $@ | ExternalFlow.cs:195:22:195:33 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:120:18:120:21 | access to array element | ExternalFlow.cs:117:36:117:47 | object creation of type Object : Object | ExternalFlow.cs:120:18:120:21 | access to array element | $@ | ExternalFlow.cs:117:36:117:47 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:188:18:188:33 | call to method GeneratedFlow | ExternalFlow.cs:187:21:187:32 | object creation of type Object : Object | ExternalFlow.cs:188:18:188:33 | call to method GeneratedFlow | $@ | ExternalFlow.cs:187:21:187:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:194:18:194:44 | call to method GeneratedFlowArgs | ExternalFlow.cs:193:22:193:33 | object creation of type Object : Object | ExternalFlow.cs:194:18:194:44 | call to method GeneratedFlowArgs | $@ | ExternalFlow.cs:193:22:193:33 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:197:18:197:44 | call to method GeneratedFlowArgs | ExternalFlow.cs:196:22:196:33 | object creation of type Object : Object | ExternalFlow.cs:197:18:197:44 | call to method GeneratedFlowArgs | $@ | ExternalFlow.cs:196:22:196:33 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:206:18:206:40 | call to method MixedFlowArgs | ExternalFlow.cs:205:22:205:33 | object creation of type Object : Object | ExternalFlow.cs:206:18:206:40 | call to method MixedFlowArgs | $@ | ExternalFlow.cs:205:22:205:33 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ql b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ql index 421216ad418..fbc4f357e10 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ql @@ -29,6 +29,7 @@ class SummaryModelTest extends SummaryModelCsv { "My.Qltest;D;false;Map<,>;(S[],System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;manual", "My.Qltest;D;false;Map<,>;(S[],System.Func);;Argument[1].ReturnValue;ReturnValue.Element;value;manual", "My.Qltest;D;false;Parse;(System.String,System.Int32);;Argument[0];Argument[1];taint;manual", + "My.Qltest;D;false;Reverse;(System.Object[]);;Argument[0].WithElement;ReturnValue;value;manual", "My.Qltest;E;true;get_MyProp;();;Argument[this].Field[My.Qltest.E.MyField];ReturnValue;value;manual", "My.Qltest;E;true;set_MyProp;(System.Object);;Argument[0];Argument[this].Field[My.Qltest.E.MyField];value;manual", "My.Qltest;G;false;GeneratedFlow;(System.Object);;Argument[0];ReturnValue;value;generated", diff --git a/csharp/ql/test/library-tests/dataflow/external-models/steps.expected b/csharp/ql/test/library-tests/dataflow/external-models/steps.expected index af0e9cdfe4b..f73872ed9be 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -19,6 +19,3 @@ summarySetterStep | Steps.cs:30:34:30:34 | 0 | Steps.cs:30:13:30:16 | [post] this access | Steps.cs:57:13:57:17 | field Field | | Steps.cs:34:37:34:37 | 0 | Steps.cs:34:13:34:16 | [post] this access | Steps.cs:63:13:63:20 | property Property | | Steps.cs:38:36:38:36 | 0 | Steps.cs:38:13:38:16 | [post] this access | file://:0:0:0:0 | element | -clearsContent -| Steps.cs:61:14:61:28 | StepFieldSetter | file://:0:0:0:0 | element | this | -| Steps.cs:67:14:67:31 | StepPropertySetter | file://:0:0:0:0 | element | this | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/steps.ql b/csharp/ql/test/library-tests/dataflow/external-models/steps.ql index ec271687a13..34b8fedf688 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/steps.ql +++ b/csharp/ql/test/library-tests/dataflow/external-models/steps.ql @@ -29,18 +29,6 @@ private class SummaryModelTest extends SummaryModelCsv { } } -private class SummarizedCallableClear extends SummarizedCallable { - SummarizedCallableClear() { - this.getName() = ["StepPropertySetter", "StepFieldSetter"] and - this.getFile().getBaseName() = "Steps.cs" - } - - override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { - pos.isThisParameter() and - content instanceof DataFlow::ElementContent - } -} - query predicate summaryThroughStep( DataFlow::Node node1, DataFlow::Node node2, boolean preservesValue ) { @@ -62,8 +50,3 @@ query predicate summarySetterStep(DataFlow::Node arg, DataFlow::Node out, Conten FlowSummaryImpl::Private::Steps::summarySetterStep(arg, c, out, any(DataFlowDispatch::DataFlowSummarizedCallable sc)) } - -query predicate clearsContent(SummarizedCallable c, DataFlow::Content k, ParameterPosition pos) { - c.clearsContent(pos, k) and - c.fromSource() -} diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index da1dca9dd24..d3955e54ff6 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -6,6 +6,7 @@ summary | Microsoft.AspNetCore.Connections;ConnectionItems;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Connections;ConnectionItems;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Connections;ConnectionItems;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Connections;ConnectionItems;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Connections;ConnectionItems;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Connections;ConnectionItems;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Connections;ConnectionItems;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -25,6 +26,7 @@ summary | Microsoft.AspNetCore.Http;HeaderDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Http;HeaderDictionary;false;Add;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Http;HeaderDictionary;false;Add;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Http;HeaderDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Http;HeaderDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Http;HeaderDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Http;HeaderDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -46,6 +48,7 @@ summary | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;Add;(System.Object,Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateEntry);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;Add;(System.Object,Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateEntry);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Mvc.ModelBinding.Validation;ValidationStateDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -71,6 +74,7 @@ summary | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;Add;(System.String,System.String);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;Add;(System.String,System.String);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;AttributeDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -82,6 +86,7 @@ summary | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;TempDataDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -93,6 +98,7 @@ summary | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Mvc.ViewFeatures;ViewDataDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -112,12 +118,14 @@ summary | Microsoft.AspNetCore.Razor.TagHelpers;NullHtmlEncoder;false;Encode;(System.IO.TextWriter,System.String,System.Int32,System.Int32);;Argument[1];Argument[0];taint;generated | | Microsoft.AspNetCore.Razor.TagHelpers;NullHtmlEncoder;false;Encode;(System.String);;Argument[0];ReturnValue;taint;generated | | Microsoft.AspNetCore.Razor.TagHelpers;TagHelperAttributeList;false;Add;(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute);;Argument[0];Argument[this].Element;value;manual | +| Microsoft.AspNetCore.Razor.TagHelpers;TagHelperAttributeList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Razor.TagHelpers;TagHelperAttributeList;false;Insert;(System.Int32,Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute);;Argument[1];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Razor.TagHelpers;TagHelperAttributeList;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | Microsoft.AspNetCore.Razor.TagHelpers;TagHelperAttributeList;false;set_Item;(System.Int32,Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute);;Argument[1];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Microsoft.AspNetCore.Routing;RouteValueDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -127,6 +135,7 @@ summary | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;set_Item;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Microsoft.AspNetCore.Routing;RouteValueDictionary;false;set_Item;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | Microsoft.AspNetCore.Server.HttpSys;UrlPrefixCollection;false;Add;(Microsoft.AspNetCore.Server.HttpSys.UrlPrefix);;Argument[0];Argument[this].Element;value;manual | +| Microsoft.AspNetCore.Server.HttpSys;UrlPrefixCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.AspNetCore.Server.HttpSys;UrlPrefixCollection;false;CopyTo;(Microsoft.AspNetCore.Server.HttpSys.UrlPrefix[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.AspNetCore.Server.HttpSys;UrlPrefixCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.AspNetCore.Server.HttpSys;UrlPrefixCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -134,19 +143,24 @@ summary | Microsoft.AspNetCore.Server.IIS.Core;ThrowingWasUpgradedWriteOnlyStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | | Microsoft.AspNetCore.Server.IIS.Core;WriteOnlyStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | Microsoft.AspNetCore.Server.IIS.Core;WriteOnlyStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | Microsoft.AspNetCore.WebUtilities;BufferedReadStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;Read;();;Argument[this];ReturnValue;taint;manual | | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;Read;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;manual | | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;Read;(System.Span);;Argument[this];ReturnValue;taint;manual | @@ -155,8 +169,18 @@ summary | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;ReadLine;();;Argument[this];ReturnValue;taint;manual | | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;ReadLineAsync;();;Argument[this];ReturnValue;taint;manual | | Microsoft.AspNetCore.WebUtilities;HttpRequestStreamReader;false;ReadToEndAsync;();;Argument[this];ReturnValue;taint;manual | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | Microsoft.CSharp.RuntimeBinder;Binder;false;BinaryOperation;(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,System.Linq.Expressions.ExpressionType,System.Type,System.Collections.Generic.IEnumerable);;Argument[2];ReturnValue;taint;generated | | Microsoft.CSharp.RuntimeBinder;Binder;false;BinaryOperation;(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,System.Linq.Expressions.ExpressionType,System.Type,System.Collections.Generic.IEnumerable);;Argument[3].Element;ReturnValue;taint;generated | | Microsoft.CSharp.RuntimeBinder;Binder;false;Convert;(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,System.Type,System.Type);;Argument[2];ReturnValue;taint;generated | @@ -363,6 +387,7 @@ summary | Microsoft.Extensions.DependencyInjection;OptionsServiceCollectionExtensions;false;ConfigureOptions;(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Type);;Argument[0].Element;ReturnValue;taint;generated | | Microsoft.Extensions.DependencyInjection;OptionsServiceCollectionExtensions;false;ConfigureOptions<>;(Microsoft.Extensions.DependencyInjection.IServiceCollection);;Argument[0].Element;ReturnValue;taint;generated | | Microsoft.Extensions.DependencyInjection;ServiceCollection;false;Add;(Microsoft.Extensions.DependencyInjection.ServiceDescriptor);;Argument[0];Argument[this].Element;value;manual | +| Microsoft.Extensions.DependencyInjection;ServiceCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.Extensions.DependencyInjection;ServiceCollection;false;CopyTo;(Microsoft.Extensions.DependencyInjection.ServiceDescriptor[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.Extensions.DependencyInjection;ServiceCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Microsoft.Extensions.DependencyInjection;ServiceCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -397,6 +422,7 @@ summary | Microsoft.Extensions.FileProviders.Internal;PhysicalDirectoryContents;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | Microsoft.Extensions.FileProviders.Internal;PhysicalDirectoryContents;false;PhysicalDirectoryContents;(System.String,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalDirectoryInfo;false;PhysicalDirectoryInfo;(System.IO.DirectoryInfo);;Argument[0];Argument[this];taint;generated | +| Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;CreateReadStream;();;Argument[this];ReturnValue;taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;PhysicalFileInfo;(System.IO.FileInfo);;Argument[0];Argument[this];taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;get_PhysicalPath;();;Argument[this];ReturnValue;taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFilesWatcher;false;PhysicalFilesWatcher;(System.String,System.IO.FileSystemWatcher,System.Boolean,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated | @@ -506,6 +532,7 @@ summary | Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | | Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[0];ReturnValue;taint;manual | | Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[this];ReturnValue;taint;manual | +| Microsoft.Extensions.Primitives;StringValues;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint;manual | | Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint;manual | | Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[0];ReturnValue;taint;manual | @@ -574,6 +601,7 @@ summary | Microsoft.Extensions.WebEncoders.Testing;UrlTestEncoder;false;Encode;(System.IO.TextWriter,System.String,System.Int32,System.Int32);;Argument[1];Argument[0];taint;generated | | Microsoft.Extensions.WebEncoders.Testing;UrlTestEncoder;false;Encode;(System.String);;Argument[0];ReturnValue;taint;generated | | Microsoft.VisualBasic;Collection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| Microsoft.VisualBasic;Collection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.VisualBasic;Collection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Microsoft.VisualBasic;Collection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | Microsoft.VisualBasic;Collection;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | @@ -590,6 +618,7 @@ summary | Microsoft.Win32;RegistryKey;false;get_Handle;();;Argument[this];ReturnValue;taint;generated | | Microsoft.Win32;RegistryKey;false;get_Name;();;Argument[this];ReturnValue;taint;generated | | Newtonsoft.Json.Linq;JArray;false;Add;(Newtonsoft.Json.Linq.JToken);;Argument[0];Argument[this].Element;value;manual | +| Newtonsoft.Json.Linq;JArray;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Newtonsoft.Json.Linq;JArray;false;CopyTo;(Newtonsoft.Json.Linq.JToken[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Newtonsoft.Json.Linq;JArray;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Newtonsoft.Json.Linq;JArray;false;Insert;(System.Int32,Newtonsoft.Json.Linq.JToken);;Argument[1];Argument[this].Element;value;manual | @@ -601,6 +630,7 @@ summary | Newtonsoft.Json.Linq;JConstructor;false;set_Item;(System.Object,Newtonsoft.Json.Linq.JToken);;Argument[1];Argument[this].Element;value;manual | | Newtonsoft.Json.Linq;JContainer;false;Add;(Newtonsoft.Json.Linq.JToken);;Argument[0];Argument[this].Element;value;manual | | Newtonsoft.Json.Linq;JContainer;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| Newtonsoft.Json.Linq;JContainer;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Newtonsoft.Json.Linq;JContainer;false;CopyTo;(Newtonsoft.Json.Linq.JToken[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Newtonsoft.Json.Linq;JContainer;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Newtonsoft.Json.Linq;JContainer;false;Find;(System.ComponentModel.PropertyDescriptor,System.Object);;Argument[this].Element;ReturnValue;value;manual | @@ -617,6 +647,7 @@ summary | Newtonsoft.Json.Linq;JObject;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | Newtonsoft.Json.Linq;JObject;false;Add;(System.String,Newtonsoft.Json.Linq.JToken);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | Newtonsoft.Json.Linq;JObject;false;Add;(System.String,Newtonsoft.Json.Linq.JToken);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| Newtonsoft.Json.Linq;JObject;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Newtonsoft.Json.Linq;JObject;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | Newtonsoft.Json.Linq;JObject;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | Newtonsoft.Json.Linq;JObject;false;JObject;(Newtonsoft.Json.Linq.JObject);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | @@ -760,6 +791,7 @@ summary | System.CodeDom.Compiler;GeneratedCodeAttribute;false;GeneratedCodeAttribute;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.CodeDom.Compiler;GeneratedCodeAttribute;false;get_Tool;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;GeneratedCodeAttribute;false;get_Version;();;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[0];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[1];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;Write;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | @@ -771,7 +803,14 @@ summary | System.CodeDom.Compiler;IndentedTextWriter;false;Write;(System.String,System.Object,System.Object);;Argument[2];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;Write;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;Write;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLine;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLine;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | @@ -784,8 +823,19 @@ summary | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLine;(System.String,System.Object,System.Object);;Argument[2];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;get_Encoding;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;get_InnerWriter;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;get_NewLine;();;Argument[this];ReturnValue;taint;generated | @@ -803,6 +853,7 @@ summary | System.Collections.Concurrent;BlockingCollection<>;false;TryAdd;(T,System.Int32,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.Collections.Concurrent;BlockingCollection<>;false;TryAdd;(T,System.TimeSpan);;Argument[0];Argument[this];taint;generated | | System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Concurrent;ConcurrentBag<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentBag<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentBag<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentBag<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -818,6 +869,7 @@ summary | System.Collections.Concurrent;ConcurrentDictionary<,>;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Concurrent;ConcurrentDictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Collections.Generic.IEnumerable>);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Collections.Generic.IEnumerable>);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | @@ -828,6 +880,7 @@ summary | System.Collections.Concurrent;ConcurrentDictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetOrAdd;(TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Item;(System.Object);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual | @@ -838,10 +891,12 @@ summary | System.Collections.Concurrent;ConcurrentDictionary<,>;false;set_Item;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;set_Item;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Concurrent;ConcurrentQueue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentQueue<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentQueue<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.Concurrent;ConcurrentQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Collections.Concurrent;ConcurrentStack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentStack<>;false;ConcurrentStack;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Concurrent;ConcurrentStack<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Concurrent;ConcurrentStack<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -862,12 +917,16 @@ summary | System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | | System.Collections.Generic;CollectionExtensions;false;Remove<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;Argument[2];taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[1];Argument[0].Element;taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[2];Argument[0].Element;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Entry;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Key;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Value;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+KeyCollection+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+KeyCollection;false;Add;(TKey);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;Dictionary<,>+KeyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Dictionary<,>+KeyCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>+KeyCollection;false;CopyTo;(TKey[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>+KeyCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Dictionary<,>+KeyCollection+Enumerator.Current];value;manual | @@ -877,6 +936,7 @@ summary | System.Collections.Generic;Dictionary<,>+KeyCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+ValueCollection+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+ValueCollection;false;Add;(TValue);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;Dictionary<,>+ValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Dictionary<,>+ValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>+ValueCollection;false;CopyTo;(TValue[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>+ValueCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Dictionary<,>+ValueCollection+Enumerator.Current];value;manual | @@ -891,6 +951,7 @@ summary | System.Collections.Generic;Dictionary<,>;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Generic;Dictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;Dictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Generic;Dictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Dictionary<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Dictionary<,>;false;Dictionary;(System.Collections.Generic.IDictionary);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | @@ -918,6 +979,7 @@ summary | System.Collections.Generic;Dictionary<,>;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Generic;HashSet<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;HashSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;HashSet<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;HashSet<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;HashSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.HashSet<>+Enumerator.Current];value;manual | | System.Collections.Generic;HashSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -927,6 +989,7 @@ summary | System.Collections.Generic;HashSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;HashSet<>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;ICollection<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;ICollection<>;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;ICollection<>;true;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;IDictionary<,>;true;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;IDictionary<,>;true;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | @@ -940,6 +1003,8 @@ summary | System.Collections.Generic;IList<>;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.Generic;IList<>;true;set_Item;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | | System.Collections.Generic;ISet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Generic;KeyValuePair<,>;false;Deconstruct;(TKey,TValue);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;KeyValuePair<,>;false;KeyValuePair;(TKey,TValue);;Argument[0];Argument[this].Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;KeyValuePair<,>;false;KeyValuePair;(TKey,TValue);;Argument[1];Argument[this].Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | @@ -971,6 +1036,7 @@ summary | System.Collections.Generic;LinkedList<>;false;AddLast;(T);;Argument[0];Argument[this];taint;generated | | System.Collections.Generic;LinkedList<>;false;AddLast;(T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Generic;LinkedList<>;false;AddLast;(T);;Argument[this];ReturnValue;taint;generated | +| System.Collections.Generic;LinkedList<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;LinkedList<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;LinkedList<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;LinkedList<>;false;Find;(T);;Argument[this].Element;ReturnValue;value;manual | @@ -995,6 +1061,7 @@ summary | System.Collections.Generic;List<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Generic;List<>;false;AddRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;manual | | System.Collections.Generic;List<>;false;AsReadOnly;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Generic;List<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;List<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;List<>;false;CopyTo;(T[]);;Argument[this];Argument[0].Element;taint;generated | | System.Collections.Generic;List<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -1037,6 +1104,7 @@ summary | System.Collections.Generic;PriorityQueue<,>;false;TryPeek;(TElement,TPriority);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;PriorityQueue<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Queue<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Generic;Queue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Queue<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Queue<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Queue<>;false;Dequeue;();;Argument[this];ReturnValue;taint;generated | @@ -1050,6 +1118,7 @@ summary | System.Collections.Generic;Queue<>;false;TryPeek;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Queue<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;Add;(TKey);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;CopyTo;(TKey[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1058,6 +1127,7 @@ summary | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;KeyCollection;(System.Collections.Generic.SortedDictionary<,>);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Generic;SortedDictionary<,>+KeyCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;SortedDictionary<,>+ValueCollection;false;Add;(TValue);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;SortedDictionary<,>+ValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;SortedDictionary<,>+ValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>+ValueCollection;false;CopyTo;(TValue[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>+ValueCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1072,6 +1142,7 @@ summary | System.Collections.Generic;SortedDictionary<,>;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Generic;SortedDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;SortedDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Generic;SortedDictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;SortedDictionary<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1097,6 +1168,7 @@ summary | System.Collections.Generic;SortedList<,>;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Generic;SortedList<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;SortedList<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Generic;SortedList<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;SortedList<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedList<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedList<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1118,6 +1190,7 @@ summary | System.Collections.Generic;SortedList<,>;false;set_Item;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;SortedList<,>;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Generic;SortedSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;SortedSet<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;SortedSet<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedSet<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;SortedSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1136,6 +1209,7 @@ summary | System.Collections.Generic;SortedSet<>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;SortedSet<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Generic;Stack<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Generic;Stack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Stack<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Stack<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Stack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1150,9 +1224,14 @@ summary | System.Collections.Generic;Stack<>;false;TryPop;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Stack<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableDictionary<,>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;IImmutableList<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Immutable;IImmutableList<>;true;AddRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableList<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;IImmutableQueue<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableSet<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;IImmutableStack<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableArray;false;Create<>;(System.Collections.Immutable.ImmutableArray,System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray;false;Create<>;(T,T);;Argument[0];ReturnValue;taint;generated | @@ -1175,6 +1254,7 @@ summary | System.Collections.Immutable;ImmutableArray<>+Builder;false;AddRange<>;(System.Collections.Immutable.ImmutableArray);;Argument[0].Element;Argument[this].Element;value;manual | | System.Collections.Immutable;ImmutableArray<>+Builder;false;AddRange<>;(System.Collections.Immutable.ImmutableArray+Builder);;Argument[0].Element;Argument[this].Element;value;manual | | System.Collections.Immutable;ImmutableArray<>+Builder;false;AddRange<>;(TDerived[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableArray<>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableArray<>+Builder;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableArray<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.Immutable;ImmutableArray<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1196,6 +1276,8 @@ summary | System.Collections.Immutable;ImmutableArray<>;false;AsMemory;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray<>;false;CastArray<>;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray<>;false;CastUp<>;(System.Collections.Immutable.ImmutableArray);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableArray<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableArray<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableArray<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableArray<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableArray<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1231,6 +1313,12 @@ summary | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[0].Element;ReturnValue;taint;generated | @@ -1247,6 +1335,7 @@ summary | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1276,6 +1365,9 @@ summary | System.Collections.Immutable;ImmutableDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableDictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableDictionary<,>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;ImmutableDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1307,6 +1399,7 @@ summary | System.Collections.Immutable;ImmutableHashSet;false;ToImmutableHashSet<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEqualityComparer);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet;false;ToImmutableHashSet<>;(System.Collections.Immutable.ImmutableHashSet+Builder);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableHashSet<>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1316,6 +1409,8 @@ summary | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;set_KeyComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | | System.Collections.Immutable;ImmutableHashSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableHashSet<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableHashSet<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableHashSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | @@ -1333,6 +1428,8 @@ summary | System.Collections.Immutable;ImmutableHashSet<>;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Immutable;ImmutableInterlocked;false;GetOrAdd<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableList;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableList;false;CreateRange<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;Remove<>;(System.Collections.Immutable.IImmutableList,T);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;RemoveRange<>;(System.Collections.Immutable.IImmutableList,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;Replace<>;(System.Collections.Immutable.IImmutableList,T,T);;Argument[0].Element;ReturnValue;taint;generated | @@ -1347,6 +1444,7 @@ summary | System.Collections.Immutable;ImmutableList<>+Builder;false;BinarySearch;(System.Int32,System.Int32,T,System.Collections.Generic.IComparer);;Argument[this];Argument[3];taint;generated | | System.Collections.Immutable;ImmutableList<>+Builder;false;BinarySearch;(T,System.Collections.Generic.IComparer);;Argument[0];Argument[1];taint;generated | | System.Collections.Immutable;ImmutableList<>+Builder;false;BinarySearch;(T,System.Collections.Generic.IComparer);;Argument[this];Argument[1];taint;generated | +| System.Collections.Immutable;ImmutableList<>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableList<>+Builder;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableList<>+Builder;false;CopyTo;(T[]);;Argument[this];Argument[0].Element;taint;generated | | System.Collections.Immutable;ImmutableList<>+Builder;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -1378,6 +1476,8 @@ summary | System.Collections.Immutable;ImmutableList<>;false;BinarySearch;(System.Int32,System.Int32,T,System.Collections.Generic.IComparer);;Argument[this];Argument[3];taint;generated | | System.Collections.Immutable;ImmutableList<>;false;BinarySearch;(T,System.Collections.Generic.IComparer);;Argument[0];Argument[1];taint;generated | | System.Collections.Immutable;ImmutableList<>;false;BinarySearch;(T,System.Collections.Generic.IComparer);;Argument[this];Argument[1];taint;generated | +| System.Collections.Immutable;ImmutableList<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableList<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableList<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableList<>;false;CopyTo;(T[]);;Argument[this];Argument[0].Element;taint;generated | | System.Collections.Immutable;ImmutableList<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -1425,6 +1525,7 @@ summary | System.Collections.Immutable;ImmutableQueue;false;CreateRange<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableQueue;false;Dequeue<>;(System.Collections.Immutable.IImmutableQueue,T);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableQueue<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableQueue<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableQueue<>;false;Dequeue;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableQueue<>;false;Dequeue;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableQueue<>;false;Enqueue;(T);;Argument[0];ReturnValue;taint;generated | @@ -1439,6 +1540,12 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[1];ReturnValue;taint;generated | @@ -1454,6 +1561,7 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1476,6 +1584,7 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_KeyComparer;(System.Collections.Generic.IComparer);;Argument[0];Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_ValueComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | @@ -1484,6 +1593,9 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1514,7 +1626,10 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;set_Item;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[1];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T[]);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateBuilder<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue;taint;generated | @@ -1524,6 +1639,7 @@ summary | System.Collections.Immutable;ImmutableSortedSet;false;ToImmutableSortedSet<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IComparer);;Argument[1];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;ToImmutableSortedSet<>;(System.Collections.Immutable.ImmutableSortedSet+Builder);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1531,6 +1647,7 @@ summary | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableSortedSet<>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;IntersectWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;Reverse;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;ToImmutable;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | @@ -1543,6 +1660,9 @@ summary | System.Collections.Immutable;ImmutableSortedSet<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | @@ -1551,8 +1671,12 @@ summary | System.Collections.Immutable;ImmutableSortedSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableSortedSet<>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableSortedSet<>;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet<>;false;Insert;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Intersect;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Remove;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Reverse;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;ToBuilder;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | @@ -1572,6 +1696,7 @@ summary | System.Collections.Immutable;ImmutableStack;false;CreateRange<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableStack;false;Pop<>;(System.Collections.Immutable.IImmutableStack,T);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableStack<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableStack<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableStack<>+Enumerator.Current];value;manual | @@ -1582,6 +1707,7 @@ summary | System.Collections.Immutable;ImmutableStack<>;false;Push;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;Collection<>;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Collections.ObjectModel;Collection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.ObjectModel;Collection<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.ObjectModel;Collection<>;false;Collection;(System.Collections.Generic.IList);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.ObjectModel;Collection<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;Collection<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -1590,23 +1716,30 @@ summary | System.Collections.ObjectModel;Collection<>;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;Collection<>;false;Insert;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;Collection<>;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.ObjectModel;Collection<>;false;get_Items;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;Collection<>;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;Collection<>;false;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;Collection<>;false;set_Item;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;KeyedCollection;(System.Collections.Generic.IEqualityComparer,System.Int32);;Argument[0];Argument[this];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;TryGetValue;(TKey,TItem);;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Dictionary;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Item;(TKey);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.ObjectModel;ReadOnlyCollection<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1620,12 +1753,14 @@ summary | System.Collections.ObjectModel;ReadOnlyCollection<>;false;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;set_Item;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;Add;(TKey);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;CopyTo;(TKey[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+KeyCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+ValueCollection;false;Add;(TValue);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.ObjectModel;ReadOnlyDictionary<,>+ValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+ValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+ValueCollection;false;CopyTo;(TValue[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>+ValueCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1638,6 +1773,7 @@ summary | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -1657,6 +1793,7 @@ summary | System.Collections.ObjectModel;ReadOnlyDictionary<,>;false;set_Item;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Specialized;HybridDictionary;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Specialized;HybridDictionary;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Specialized;HybridDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;HybridDictionary;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;HybridDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.Specialized;HybridDictionary;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | @@ -1671,6 +1808,7 @@ summary | System.Collections.Specialized;IOrderedDictionary;true;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Specialized;ListDictionary;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Specialized;ListDictionary;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Specialized;ListDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;ListDictionary;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;ListDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.Specialized;ListDictionary;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | @@ -1705,6 +1843,7 @@ summary | System.Collections.Specialized;NameObjectCollectionBase;true;get_Keys;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;NameValueCollection;false;Add;(System.Collections.Specialized.NameValueCollection);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Specialized;NameValueCollection;false;Add;(System.String,System.String);;Argument[0];Argument[this];taint;generated | +| System.Collections.Specialized;NameValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;NameValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;NameValueCollection;false;Get;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;NameValueCollection;false;Get;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -1729,6 +1868,7 @@ summary | System.Collections.Specialized;OrderedDictionary;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Specialized;OrderedDictionary;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Specialized;OrderedDictionary;false;AsReadOnly;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Specialized;OrderedDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;OrderedDictionary;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;OrderedDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.Specialized;OrderedDictionary;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | @@ -1746,6 +1886,7 @@ summary | System.Collections.Specialized;StringCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Specialized;StringCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Specialized;StringCollection;false;AddRange;(System.String[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Specialized;StringCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;StringCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;StringCollection;false;CopyTo;(System.String[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;StringCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1756,6 +1897,7 @@ summary | System.Collections.Specialized;StringCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;StringCollection;false;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections.Specialized;StringCollection;false;set_Item;(System.Int32,System.String);;Argument[1];Argument[this].Element;value;manual | +| System.Collections.Specialized;StringDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;StringDictionary;false;CopyTo;(System.Array,System.Int32);;Argument[this];Argument[0].Element;taint;generated | | System.Collections.Specialized;StringDictionary;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections.Specialized;StringDictionary;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -1765,6 +1907,7 @@ summary | System.Collections;ArrayList;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Collections;ArrayList;false;AddRange;(System.Collections.ICollection);;Argument[0].Element;Argument[this].Element;value;manual | | System.Collections;ArrayList;false;ArrayList;(System.Collections.ICollection);;Argument[0].Element;Argument[this];taint;generated | +| System.Collections;ArrayList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;ArrayList;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;ArrayList;false;CopyTo;(System.Array);;Argument[this];Argument[0].Element;taint;generated | | System.Collections;ArrayList;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | @@ -1797,10 +1940,12 @@ summary | System.Collections;BitArray;false;Xor;(System.Collections.BitArray);;Argument[this];ReturnValue;value;generated | | System.Collections;BitArray;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections;CollectionBase;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.Collections;CollectionBase;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;CollectionBase;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;CollectionBase;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections;CollectionBase;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[0];Argument[this];taint;generated | +| System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[this];Argument[0];taint;generated | | System.Collections;CollectionBase;false;get_InnerList;();;Argument[this];ReturnValue;taint;generated | | System.Collections;CollectionBase;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections;CollectionBase;false;get_List;();;Argument[this];ReturnValue;taint;generated | @@ -1809,6 +1954,7 @@ summary | System.Collections;Comparer;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | | System.Collections;DictionaryBase;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;DictionaryBase;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;DictionaryBase;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;DictionaryBase;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;DictionaryBase;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections;DictionaryBase;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | @@ -1830,6 +1976,7 @@ summary | System.Collections;DictionaryEntry;false;set_Value;(System.Object);;Argument[0];Argument[this];taint;generated | | System.Collections;Hashtable;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;Hashtable;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;Hashtable;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;Hashtable;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;Hashtable;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;Hashtable;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1865,6 +2012,7 @@ summary | System.Collections;ICollection;true;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;IDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;IDictionary;true;get_Item;(System.Object);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual | | System.Collections;IDictionary;true;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual | | System.Collections;IDictionary;true;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | @@ -1872,9 +2020,11 @@ summary | System.Collections;IDictionary;true;set_Item;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections;IEnumerable;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections;IList;true;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.Collections;IList;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;IList;true;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections;IList;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections;IList;true;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | +| System.Collections;Queue;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;Queue;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;Queue;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;Queue;false;Dequeue;();;Argument[this];ReturnValue;taint;generated | @@ -1890,6 +2040,7 @@ summary | System.Collections;ReadOnlyCollectionBase;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections;SortedList;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;SortedList;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;SortedList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;SortedList;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;SortedList;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;SortedList;false;GetByIndex;(System.Int32);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual | @@ -1911,6 +2062,7 @@ summary | System.Collections;SortedList;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | | System.Collections;SortedList;false;set_Item;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;SortedList;false;set_Item;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;Stack;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;Stack;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;Stack;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;Stack;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1989,6 +2141,7 @@ summary | System.ComponentModel.Design;DesignerCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.ComponentModel.Design;DesignerCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.ComponentModel.Design;DesignerOptionService+DesignerOptionCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.ComponentModel.Design;DesignerOptionService+DesignerOptionCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel.Design;DesignerOptionService+DesignerOptionCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.ComponentModel.Design;DesignerOptionService+DesignerOptionCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.ComponentModel.Design;DesignerOptionService+DesignerOptionCollection;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | @@ -2031,7 +2184,9 @@ summary | System.ComponentModel;BaseNumberConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | | System.ComponentModel;BindingList<>;false;Find;(System.ComponentModel.PropertyDescriptor,System.Object);;Argument[this].Element;ReturnValue;value;manual | | System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.ComponentModel;CategoryAttribute;false;CategoryAttribute;(System.String);;Argument[0];Argument[this];taint;generated | | System.ComponentModel;CategoryAttribute;false;get_Category;();;Argument[this];ReturnValue;taint;generated | | System.ComponentModel;CharConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | @@ -2074,6 +2229,7 @@ summary | System.ComponentModel;EnumConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | | System.ComponentModel;EventDescriptorCollection;false;Add;(System.ComponentModel.EventDescriptor);;Argument[0];Argument[this].Element;value;manual | | System.ComponentModel;EventDescriptorCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.ComponentModel;EventDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel;EventDescriptorCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.ComponentModel;EventDescriptorCollection;false;EventDescriptorCollection;(System.ComponentModel.EventDescriptor[]);;Argument[0].Element;Argument[this];taint;generated | | System.ComponentModel;EventDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual | @@ -2109,6 +2265,7 @@ summary | System.ComponentModel;LicenseProviderAttribute;false;get_LicenseProvider;();;Argument[this];ReturnValue;taint;generated | | System.ComponentModel;LicenseProviderAttribute;false;get_TypeId;();;Argument[this];ReturnValue;taint;generated | | System.ComponentModel;ListSortDescriptionCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.ComponentModel;ListSortDescriptionCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel;ListSortDescriptionCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.ComponentModel;ListSortDescriptionCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.ComponentModel;ListSortDescriptionCollection;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | @@ -2171,6 +2328,7 @@ summary | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.ComponentModel;PropertyDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -2295,6 +2453,7 @@ summary | System.Data.Common;DataColumnMappingCollection;false;Add;(System.String,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DataColumnMappingCollection;false;AddRange;(System.Array);;Argument[0].Element;Argument[this].Element;value;manual | | System.Data.Common;DataColumnMappingCollection;false;AddRange;(System.Data.Common.DataColumnMapping[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data.Common;DataColumnMappingCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data.Common;DataColumnMappingCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DataColumnMappingCollection;false;CopyTo;(System.Data.Common.DataColumnMapping[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DataColumnMappingCollection;false;GetByDataSetColumn;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -2334,6 +2493,7 @@ summary | System.Data.Common;DataTableMappingCollection;false;Add;(System.String,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DataTableMappingCollection;false;AddRange;(System.Array);;Argument[0].Element;Argument[this].Element;value;manual | | System.Data.Common;DataTableMappingCollection;false;AddRange;(System.Data.Common.DataTableMapping[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data.Common;DataTableMappingCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data.Common;DataTableMappingCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DataTableMappingCollection;false;CopyTo;(System.Data.Common.DataTableMapping[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DataTableMappingCollection;false;GetByDataSetTable;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -2354,11 +2514,16 @@ summary | System.Data.Common;DbBatchCommandCollection;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Data.Common;DbBatchCommandCollection;false;set_Item;(System.Int32,System.Data.Common.DbBatchCommand);;Argument[1];Argument[this].Element;value;manual | | System.Data.Common;DbBatchCommandCollection;true;Add;(System.Data.Common.DbBatchCommand);;Argument[0];Argument[this].Element;value;manual | +| System.Data.Common;DbBatchCommandCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data.Common;DbBatchCommandCollection;true;CopyTo;(System.Data.Common.DbBatchCommand[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DbBatchCommandCollection;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Data.Common;DbBatchCommandCollection;true;Insert;(System.Int32,System.Data.Common.DbBatchCommand);;Argument[1];Argument[this].Element;value;manual | | System.Data.Common;DbCommand;false;ExecuteReader;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;ExecuteReader;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;();;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Connection;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Parameters;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Transaction;();;Argument[this];ReturnValue;taint;generated | @@ -2366,6 +2531,7 @@ summary | System.Data.Common;DbCommand;false;set_Connection;(System.Data.IDbConnection);;Argument[0];Argument[this];taint;generated | | System.Data.Common;DbCommand;false;set_Transaction;(System.Data.Common.DbTransaction);;Argument[0];Argument[this];taint;generated | | System.Data.Common;DbCommand;false;set_Transaction;(System.Data.IDbTransaction);;Argument[0];Argument[this];taint;generated | +| System.Data.Common;DbCommand;true;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;true;PrepareAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;(System.Boolean);;Argument[this];ReturnValue;taint;generated | @@ -2396,8 +2562,10 @@ summary | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String);;Argument[2];Argument[0];taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[1];Argument[0];taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[2];Argument[0];taint;generated | +| System.Data.Common;DbConnectionStringBuilder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data.Common;DbConnectionStringBuilder;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DbConnectionStringBuilder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Data.Common;DbConnectionStringBuilder;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetProperties;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetProperties;(System.Attribute[]);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated | @@ -2432,10 +2600,13 @@ summary | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[0];ReturnValue;taint;generated | | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[1];ReturnValue;taint;generated | | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[3];ReturnValue;taint;generated | +| System.Data.Common;DbDataReader;false;GetFieldValueAsync<>;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Data.Common;DbDataReader;true;GetFieldValue<>;(System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbDataReader;true;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetProviderSpecificValue;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetProviderSpecificValues;(System.Object[]);;Argument[this];Argument[0].Element;taint;generated | +| System.Data.Common;DbDataReader;true;GetSchemaTableAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetTextReader;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataRecord;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated | | System.Data.Common;DbEnumerator;false;DbEnumerator;(System.Data.IDataReader);;Argument[0];Argument[this];taint;generated | @@ -2451,6 +2622,7 @@ summary | System.Data.Common;DbParameterCollection;false;set_Item;(System.String,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Data.Common;DbParameterCollection;true;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Data.Common;DbParameterCollection;true;AddRange;(System.Array);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data.Common;DbParameterCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data.Common;DbParameterCollection;true;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data.Common;DbParameterCollection;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Data.Common;DbParameterCollection;true;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | @@ -2544,6 +2716,7 @@ summary | System.Data;ConstraintCollection;false;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[0];Argument[this];taint;generated | | System.Data;ConstraintCollection;false;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[0];ReturnValue;taint;generated | | System.Data;ConstraintCollection;false;AddRange;(System.Data.Constraint[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;ConstraintCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;ConstraintCollection;false;CopyTo;(System.Data.Constraint[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;ConstraintCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;ConstraintCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -2576,15 +2749,20 @@ summary | System.Data;DataColumn;false;set_Prefix;(System.String);;Argument[0];Argument[this];taint;generated | | System.Data;DataColumnChangeEventArgs;false;DataColumnChangeEventArgs;(System.Data.DataRow,System.Data.DataColumn,System.Object);;Argument[1];Argument[this];taint;generated | | System.Data;DataColumnChangeEventArgs;false;get_Column;();;Argument[this];ReturnValue;taint;generated | +| System.Data;DataColumnCollection;false;Add;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;Add;(System.Data.DataColumn);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataColumnCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | +| System.Data;DataColumnCollection;false;Add;(System.String,System.Type);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataColumnCollection;false;Add;(System.String,System.Type,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;AddRange;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataColumnCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataColumnCollection;false;CopyTo;(System.Data.DataColumn[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataColumnCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;get_List;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetDateTime;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetFieldValue<>;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | +| System.Data;DataReaderExtensions;false;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetGuid;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetProviderSpecificValue;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetString;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | @@ -2616,11 +2794,18 @@ summary | System.Data;DataRelationCollection;false;Add;(System.Data.DataRelation);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataRelationCollection;false;CopyTo;(System.Data.DataRelation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataRelationCollection;false;Remove;(System.Data.DataRelation);;Argument[0];Argument[this];taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;AddRange;(System.Data.DataRelation[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataRelationCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataRow;false;DataRow;(System.Data.DataRowBuilder);;Argument[0];Argument[this];taint;generated | | System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation,System.Data.DataRowVersion);;Argument[this];ReturnValue;taint;generated | @@ -2645,6 +2830,7 @@ summary | System.Data;DataRow;false;set_RowError;(System.String);;Argument[0];Argument[this];taint;generated | | System.Data;DataRowCollection;false;Add;(System.Data.DataRow);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataRowCollection;false;Add;(System.Object[]);;Argument[0];Argument[this].Element;value;manual | +| System.Data;DataRowCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataRowCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataRowCollection;false;CopyTo;(System.Data.DataRow[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataRowCollection;false;Find;(System.Object);;Argument[this].Element;ReturnValue;value;manual | @@ -2725,11 +2911,14 @@ summary | System.Data;DataTable;false;set_PrimaryKey;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this];taint;generated | | System.Data;DataTable;false;set_Site;(System.ComponentModel.ISite);;Argument[0];Argument[this];taint;generated | | System.Data;DataTable;false;set_TableName;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Data;DataTableCollection;false;Add;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;Add;(System.Data.DataTable);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataTableCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];ReturnValue;taint;generated | +| System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;AddRange;(System.Data.DataTable[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataTableCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataTableCollection;false;CopyTo;(System.Data.DataTable[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataTableCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -2751,6 +2940,7 @@ summary | System.Data;DataView;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataView;false;AddNew;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataView;false;ApplySort;(System.ComponentModel.PropertyDescriptor,System.ComponentModel.ListSortDirection);;Argument[0];Argument[this];taint;generated | +| System.Data;DataView;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataView;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataView;false;DataView;(System.Data.DataTable,System.String,System.String,System.Data.DataViewRowState);;Argument[0];Argument[this];taint;generated | | System.Data;DataView;false;DataView;(System.Data.DataTable,System.String,System.String,System.Data.DataViewRowState);;Argument[2];Argument[this];taint;generated | @@ -2780,6 +2970,7 @@ summary | System.Data;DataView;false;set_Sort;(System.String);;Argument[0];Argument[this];taint;generated | | System.Data;DataView;false;set_Table;(System.Data.DataTable);;Argument[0];Argument[this];taint;generated | | System.Data;DataViewManager;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.Data;DataViewManager;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataViewManager;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataViewManager;false;CreateDataView;(System.Data.DataTable);;Argument[this];ReturnValue;taint;generated | | System.Data;DataViewManager;false;Find;(System.ComponentModel.PropertyDescriptor,System.Object);;Argument[this].Element;ReturnValue;value;manual | @@ -2972,6 +3163,7 @@ summary | System.Diagnostics;ActivityTagsCollection;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | System.Diagnostics;ActivityTagsCollection;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Diagnostics;ActivityTagsCollection;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Diagnostics;ActivityTagsCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Diagnostics;ActivityTagsCollection;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Diagnostics;ActivityTagsCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Diagnostics;ActivityTagsCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -3097,6 +3289,7 @@ summary | System.Diagnostics;SwitchLevelAttribute;false;set_SwitchLevelType;(System.Type);;Argument[0];Argument[this];taint;generated | | System.Diagnostics;TagList+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Diagnostics;TagList;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | +| System.Diagnostics;TagList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Diagnostics;TagList;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Diagnostics;TagList;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Diagnostics;TagList;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -3121,6 +3314,7 @@ summary | System.Diagnostics;TraceListenerCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Diagnostics;TraceListenerCollection;false;AddRange;(System.Diagnostics.TraceListenerCollection);;Argument[0].Element;Argument[this].Element;value;manual | | System.Diagnostics;TraceListenerCollection;false;AddRange;(System.Diagnostics.TraceListener[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Diagnostics;TraceListenerCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Diagnostics;TraceListenerCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Diagnostics;TraceListenerCollection;false;CopyTo;(System.Diagnostics.TraceListener[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Diagnostics;TraceListenerCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -3170,6 +3364,7 @@ summary | System.Dynamic;ExpandoObject;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | System.Dynamic;ExpandoObject;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Dynamic;ExpandoObject;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Dynamic;ExpandoObject;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Dynamic;ExpandoObject;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Dynamic;ExpandoObject;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Dynamic;ExpandoObject;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -3342,10 +3537,13 @@ summary | System.IO.Compression;BrotliStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;BrotliStream;false;BrotliStream;(System.IO.Stream,System.IO.Compression.CompressionMode,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Compression;BrotliStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;BrotliStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;BrotliStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;BrotliStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO.Compression;BrotliStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;BrotliStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;BrotliStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Compression;BrotliStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;BrotliStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;DeflateStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;DeflateStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | @@ -3356,32 +3554,41 @@ summary | System.IO.Compression;DeflateStream;false;DeflateStream;(System.IO.Stream,System.IO.Compression.CompressionMode);;Argument[0];Argument[this];taint;manual | | System.IO.Compression;DeflateStream;false;DeflateStream;(System.IO.Stream,System.IO.Compression.CompressionMode,System.Boolean);;Argument[0];Argument[this];taint;manual | | System.IO.Compression;DeflateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;DeflateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;DeflateStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;DeflateStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO.Compression;DeflateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;DeflateStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;DeflateStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Compression;DeflateStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;DeflateStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;GZipStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;GZipStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;GZipStream;false;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO.Compression;GZipStream;false;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | | System.IO.Compression;GZipStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;GZipStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;GZipStream;false;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Compression;GZipStream;false;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Compression;GZipStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;GZipStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO.Compression;GZipStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;GZipStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;GZipStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Compression;GZipStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;GZipStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZLibStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;ZLibStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;ZLibStream;false;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO.Compression;ZLibStream;false;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | | System.IO.Compression;ZLibStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;ZLibStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZLibStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Compression;ZLibStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO.Compression;ZLibStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZLibStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Compression;ZLibStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Compression;ZLibStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZLibStream;false;ZLibStream;(System.IO.Stream,System.IO.Compression.CompressionLevel,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Compression;ZLibStream;false;ZLibStream;(System.IO.Stream,System.IO.Compression.CompressionMode,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Compression;ZLibStream;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | @@ -3399,7 +3606,10 @@ summary | System.IO.Compression;ZipArchiveEntry;false;get_LastWriteTime;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZipArchiveEntry;false;get_Name;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZipArchiveEntry;false;set_LastWriteTime;(System.DateTimeOffset);;Argument[0];Argument[this];taint;generated | +| System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[2];ReturnValue;taint;generated | +| System.IO.Compression;ZipFile;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[2];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String,System.IO.Compression.CompressionLevel);;Argument[0];ReturnValue;taint;generated | @@ -3417,6 +3627,7 @@ summary | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO.IsolatedStorage;IsolatedStorageFileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | @@ -3427,6 +3638,11 @@ summary | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.IO.FileStream,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess,System.IO.HandleInheritability,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess);;Argument[0];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedFile;false;get_SafeMemoryMappedFileHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedViewAccessor;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedViewStream;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated | @@ -3456,11 +3672,14 @@ summary | System.IO.Pipes;NamedPipeServerStream;false;WaitForConnectionAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO.Pipes;PipeStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Pipes;PipeStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Pipes;PipeStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Pipes;PipeStream;false;InitializeHandle;(Microsoft.Win32.SafeHandles.SafePipeHandle,System.Boolean,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO.Pipes;PipeStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO.Pipes;PipeStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO.Pipes;PipeStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Pipes;PipeStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO.Pipes;PipeStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO.Pipes;PipeStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.Pipes;PipeStream;false;get_SafePipeHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO;BinaryReader;false;BinaryReader;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO;BinaryReader;false;BinaryReader;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[1];Argument[this];taint;generated | @@ -3470,6 +3689,7 @@ summary | System.IO;BinaryReader;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[1];Argument[this];taint;generated | +| System.IO;BinaryWriter;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;BinaryWriter;false;Write;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;BinaryWriter;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;BinaryWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | @@ -3478,10 +3698,13 @@ summary | System.IO;BufferedStream;false;BufferedStream;(System.IO.Stream,System.Int32);;Argument[0];Argument[this];taint;generated | | System.IO;BufferedStream;false;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;BufferedStream;false;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | +| System.IO;BufferedStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;BufferedStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;BufferedStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO;BufferedStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;BufferedStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO;BufferedStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO;BufferedStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;BufferedStream;false;get_UnderlyingStream;();;Argument[this];ReturnValue;taint;generated | | System.IO;Directory;false;CreateDirectory;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;Directory;false;CreateSymbolicLink;(System.String,System.String);;Argument[0];ReturnValue;taint;generated | @@ -3518,8 +3741,19 @@ summary | System.IO;File;false;AppendAllLinesAsync;(System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Text.Encoding,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | | System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String,System.Int32);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String,System.Int32,System.IO.FileOptions);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;CreateSymbolicLink;(System.String,System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;OpenHandle;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.Int64);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenText;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenWrite;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;ReadAllText;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;ReadAllText;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[1];ReturnValue;taint;generated | @@ -3530,8 +3764,15 @@ summary | System.IO;File;false;WriteAllTextAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.IO;FileInfo;false;CopyTo;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;FileInfo;false;CopyTo;(System.String,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Create;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;MoveTo;(System.String);;Argument[0];Argument[this];taint;generated | | System.IO;FileInfo;false;MoveTo;(System.String,System.Boolean);;Argument[0];Argument[this];taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenRead;();;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenText;();;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenWrite;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;get_Directory;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;get_DirectoryName;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;get_Name;();;Argument[this];ReturnValue;taint;generated | @@ -3550,6 +3791,7 @@ summary | System.IO;FileStream;false;FileStream;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32,System.Boolean);;Argument[0];Argument[this];taint;manual | | System.IO;FileStream;false;FileStream;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32,System.IO.FileOptions);;Argument[0];Argument[this];taint;manual | | System.IO;FileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO;FileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;FileStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;FileStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | | System.IO;FileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | @@ -3584,6 +3826,7 @@ summary | System.IO;MemoryStream;false;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;MemoryStream;false;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | | System.IO;MemoryStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO;MemoryStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;MemoryStream;false;GetBuffer;();;Argument[this];ReturnValue;taint;generated | | System.IO;MemoryStream;false;MemoryStream;(System.Byte[]);;Argument[0];Argument[this];taint;manual | | System.IO;MemoryStream;false;MemoryStream;(System.Byte[],System.Boolean);;Argument[0].Element;Argument[this];taint;manual | @@ -3592,10 +3835,12 @@ summary | System.IO;MemoryStream;false;MemoryStream;(System.Byte[],System.Int32,System.Int32,System.Boolean,System.Boolean);;Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;MemoryStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO;MemoryStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;MemoryStream;false;ToArray;();;Argument[this];ReturnValue;taint;manual | | System.IO;MemoryStream;false;TryGetBuffer;(System.ArraySegment);;Argument[this];ReturnValue;taint;generated | | System.IO;MemoryStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO;MemoryStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;MemoryStream;false;WriteTo;(System.IO.Stream);;Argument[this];Argument[0];taint;generated | | System.IO;Path;false;ChangeExtension;(System.String,System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;Path;false;Combine;(System.String,System.String);;Argument[0];ReturnValue;taint;manual | @@ -3651,6 +3896,7 @@ summary | System.IO;Stream;false;CopyToAsync;(System.IO.Stream);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;false;CopyToAsync;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;false;CopyToAsync;(System.IO.Stream,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | +| System.IO;Stream;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;Stream;false;Synchronized;(System.IO.Stream);;Argument[0];ReturnValue;taint;generated | | System.IO;Stream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | @@ -3658,10 +3904,13 @@ summary | System.IO;Stream;true;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO;Stream;true;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;true;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | +| System.IO;Stream;true;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;true;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;Stream;true;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO;Stream;true;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;true;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO;Stream;true;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO;Stream;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;StreamReader;false;Read;();;Argument[this];ReturnValue;taint;manual | | System.IO;StreamReader;false;Read;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;manual | | System.IO;StreamReader;false;Read;(System.Span);;Argument[this];ReturnValue;taint;manual | @@ -3690,6 +3939,7 @@ summary | System.IO;StreamReader;false;StreamReader;(System.String,System.Text.Encoding,System.Boolean,System.Int32);;Argument[0];Argument[this];taint;manual | | System.IO;StreamReader;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO;StreamReader;false;get_CurrentEncoding;();;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;StreamWriter;false;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO;StreamWriter;false;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32,System.Boolean);;Argument[1];Argument[this];taint;generated | | System.IO;StreamWriter;false;Write;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | @@ -3704,7 +3954,14 @@ summary | System.IO;StreamWriter;false;Write;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;StreamWriter;false;Write;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;StreamWriter;false;Write;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;StreamWriter;false;WriteLine;(System.String);;Argument[0];Argument[this];taint;generated | | System.IO;StreamWriter;false;WriteLine;(System.String,System.Object);;Argument[0];Argument[this];taint;generated | | System.IO;StreamWriter;false;WriteLine;(System.String,System.Object);;Argument[1];Argument[this];taint;generated | @@ -3717,7 +3974,15 @@ summary | System.IO;StreamWriter;false;WriteLine;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;StreamWriter;false;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;StreamWriter;false;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;StreamWriter;false;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;StreamWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO;StreamWriter;false;get_Encoding;();;Argument[this];ReturnValue;taint;generated | | System.IO;StringReader;false;Read;();;Argument[this];ReturnValue;taint;manual | @@ -3733,19 +3998,39 @@ summary | System.IO;StringReader;false;ReadToEnd;();;Argument[this];ReturnValue;taint;manual | | System.IO;StringReader;false;ReadToEndAsync;();;Argument[this];ReturnValue;taint;manual | | System.IO;StringReader;false;StringReader;(System.String);;Argument[0];Argument[this];taint;manual | +| System.IO;StringWriter;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;GetStringBuilder;();;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;StringWriter;(System.Text.StringBuilder,System.IFormatProvider);;Argument[0];Argument[this];taint;generated | | System.IO;StringWriter;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;Write;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;StringWriter;false;Write;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;Write;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLine;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;TextReader;false;Synchronized;(System.IO.TextReader);;Argument[0];ReturnValue;taint;generated | | System.IO;TextReader;true;Read;();;Argument[this];ReturnValue;taint;manual | | System.IO;TextReader;true;Read;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;manual | @@ -3763,7 +4048,12 @@ summary | System.IO;TextWriter;false;Synchronized;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;false;TextWriter;(System.IFormatProvider);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;Write;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.Object);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object);;Argument[0];Argument[this];taint;generated | @@ -3777,7 +4067,14 @@ summary | System.IO;TextWriter;true;Write;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLine;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | @@ -3794,8 +4091,18 @@ summary | System.IO;TextWriter;true;WriteLine;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteLine;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;get_FormatProvider;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;get_NewLine;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;set_NewLine;(System.String);;Argument[0];Argument[this];taint;generated | @@ -3803,16 +4110,19 @@ summary | System.IO;UnmanagedMemoryAccessor;false;UnmanagedMemoryAccessor;(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryAccessor;false;UnmanagedMemoryAccessor;(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64,System.IO.FileAccess);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.IO;UnmanagedMemoryStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;UnmanagedMemoryStream;false;Initialize;(System.Byte*,System.Int64,System.Int64,System.IO.FileAccess);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;Initialize;(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64,System.IO.FileAccess);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;UnmanagedMemoryStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO;UnmanagedMemoryStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;UnmanagedMemoryStream;false;UnmanagedMemoryStream;(System.Byte*,System.Int64);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;UnmanagedMemoryStream;(System.Byte*,System.Int64,System.Int64,System.IO.FileAccess);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;UnmanagedMemoryStream;(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;UnmanagedMemoryStream;(System.Runtime.InteropServices.SafeBuffer,System.Int64,System.Int64,System.IO.FileAccess);;Argument[0];Argument[this];taint;generated | | System.IO;UnmanagedMemoryStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO;UnmanagedMemoryStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO;UnmanagedMemoryStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;UnmanagedMemoryStream;false;get_PositionPointer;();;Argument[this];ReturnValue;taint;generated | | System.Linq.Expressions;BinaryExpression;false;Accept;(System.Linq.Expressions.ExpressionVisitor);;Argument[this];Argument[0];taint;generated | | System.Linq.Expressions;BinaryExpression;false;Accept;(System.Linq.Expressions.ExpressionVisitor);;Argument[this];ReturnValue;taint;generated | @@ -5055,15 +5365,18 @@ summary | System.Net.Http.Headers;HeaderStringValues;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HeaderStringValues;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeaderValueCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Net.Http.Headers;HttpHeaderValueCollection<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.Http.Headers;HttpHeaderValueCollection<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.Http.Headers;HttpHeaderValueCollection<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.Http.Headers;HttpHeaderValueCollection<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Net.Http.Headers;HttpHeaders;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.Http.Headers;HttpHeaders;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.Http.Headers;HttpHeaders;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.Http.Headers;HttpHeaders;false;get_NonValidated;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.Http.Headers;HttpHeadersNonValidated;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Net.Http.Headers;HttpHeadersNonValidated;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValue;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValues;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;get_Item;(System.String);;Argument[0];ReturnValue;taint;generated | @@ -5161,18 +5474,29 @@ summary | System.Net.Http.Headers;WarningHeaderValue;false;get_Text;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Json;JsonContent;false;Create;(System.Object,System.Type,System.Net.Http.Headers.MediaTypeHeaderValue,System.Text.Json.JsonSerializerOptions);;Argument[3];ReturnValue;taint;generated | | System.Net.Http.Json;JsonContent;false;Create<>;(T,System.Net.Http.Headers.MediaTypeHeaderValue,System.Text.Json.JsonSerializerOptions);;Argument[2];ReturnValue;taint;generated | +| System.Net.Http.Json;JsonContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http.Json;JsonContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http.Json;JsonContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Http;ByteArrayContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;ByteArrayContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;DelegatingHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated | | System.Net.Http;DelegatingHandler;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;get_InnerHandler;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;set_InnerHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage);;Argument[this];Argument[0];taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption);;Argument[this];Argument[0];taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | @@ -5199,7 +5523,10 @@ summary | System.Net.Http;HttpContent;false;ReadAsStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpContent;false;get_Headers;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpContent;true;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;HttpContent;true;CreateContentReadStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpMessageInvoker;false;HttpMessageInvoker;(System.Net.Http.HttpMessageHandler,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Http;HttpMessageInvoker;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Http;HttpMethod;false;HttpMethod;(System.String);;Argument[0];Argument[this];taint;generated | @@ -5221,6 +5548,7 @@ summary | System.Net.Http;HttpRequestOptions;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | System.Net.Http;HttpRequestOptions;false;Add;(System.String,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Net.Http;HttpRequestOptions;false;Add;(System.String,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Net.Http;HttpRequestOptions;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.Http;HttpRequestOptions;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.Http;HttpRequestOptions;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.Http;HttpRequestOptions;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -5241,19 +5569,27 @@ summary | System.Net.Http;MessageProcessingHandler;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Http;MultipartContent;false;Add;(System.Net.Http.HttpContent);;Argument[0];Argument[this].Element;value;manual | | System.Net.Http;MultipartContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;MultipartContent;false;CreateContentReadStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;MultipartContent;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.Http;MultipartContent;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.Http;MultipartContent;false;MultipartContent;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.Net.Http;MultipartContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | | System.Net.Http;MultipartContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;MultipartContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;MultipartContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;MultipartContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent);;Argument[0];Argument[this].Element;value;manual | | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent,System.String);;Argument[0];Argument[this];taint;generated | | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent,System.String,System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;MultipartFormDataContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;MultipartFormDataContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;MultipartFormDataContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ReadOnlyMemoryContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;ReadOnlyMemoryContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ReadOnlyMemoryContent;false;ReadOnlyMemoryContent;(System.ReadOnlyMemory);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;ReadOnlyMemoryContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;ReadOnlyMemoryContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ReadOnlyMemoryContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;SocketsHttpConnectionContext;false;get_DnsEndPoint;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;SocketsHttpConnectionContext;false;get_InitialRequestMessage;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;SocketsHttpHandler;false;get_ActivityHeadersPropagator;();;Argument[this];ReturnValue;taint;generated | @@ -5292,11 +5628,19 @@ summary | System.Net.Http;SocketsHttpPlaintextStreamFilterContext;false;get_PlaintextStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | | System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream,System.Int32);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[0];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[1];ReturnValue;taint;generated | @@ -5326,7 +5670,10 @@ summary | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.String);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;get_ContentId;();;Argument[this];ReturnValue;taint;generated | | System.Net.Mail;AttachmentBase;false;get_ContentStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Mail;AttachmentBase;false;set_ContentType;(System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | @@ -5417,31 +5764,37 @@ summary | System.Net.Mime;ContentType;false;get_Parameters;();;Argument[this];ReturnValue;taint;generated | | System.Net.Mime;ContentType;false;set_MediaType;(System.String);;Argument[0];Argument[this];taint;generated | | System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;Add;(System.Net.NetworkInformation.GatewayIPAddressInformation);;Argument[0];Argument[this].Element;value;manual | +| System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;CopyTo;(System.Net.NetworkInformation.GatewayIPAddressInformation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.NetworkInformation;GatewayIPAddressInformationCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Net.NetworkInformation;IPAddressCollection;false;Add;(System.Net.IPAddress);;Argument[0];Argument[this].Element;value;manual | +| System.Net.NetworkInformation;IPAddressCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.NetworkInformation;IPAddressCollection;false;CopyTo;(System.Net.IPAddress[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.NetworkInformation;IPAddressCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.NetworkInformation;IPAddressCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.NetworkInformation;IPAddressInformationCollection;false;Add;(System.Net.NetworkInformation.IPAddressInformation);;Argument[0];Argument[this].Element;value;manual | +| System.Net.NetworkInformation;IPAddressInformationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.NetworkInformation;IPAddressInformationCollection;false;CopyTo;(System.Net.NetworkInformation.IPAddressInformation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.NetworkInformation;IPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.NetworkInformation;IPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.NetworkInformation;IPAddressInformationCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;Add;(System.Net.NetworkInformation.MulticastIPAddressInformation);;Argument[0];Argument[this].Element;value;manual | +| System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;CopyTo;(System.Net.NetworkInformation.MulticastIPAddressInformation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.NetworkInformation;MulticastIPAddressInformationCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Net.NetworkInformation;PhysicalAddress;false;PhysicalAddress;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;Add;(System.Net.NetworkInformation.UnicastIPAddressInformation);;Argument[0];Argument[this].Element;value;manual | +| System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;CopyTo;(System.Net.NetworkInformation.UnicastIPAddressInformation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;AuthenticatedStream;false;AuthenticatedStream;(System.IO.Stream,System.Boolean);;Argument[0];Argument[this];taint;generated | +| System.Net.Security;AuthenticatedStream;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;AuthenticatedStream;false;get_InnerStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[1];Argument[this];taint;generated | | System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[2];Argument[this];taint;generated | @@ -5462,6 +5815,7 @@ summary | System.Net.Security;NegotiateStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Security;NegotiateStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.Net.Security;NegotiateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Security;NegotiateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Security;NegotiateStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | @@ -5480,11 +5834,14 @@ summary | System.Net.Security;SslStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Security;SslStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.Net.Security;SslStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Net.Security;SslStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Security;SslStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.Net.Security;SslStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslStream;false;Write;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Security;SslStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.Net.Security;SslStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.Net.Security;SslStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslStream;false;get_LocalCertificate;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslStream;false;get_NegotiatedApplicationProtocol;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslStream;false;get_RemoteCertificate;();;Argument[this];ReturnValue;taint;generated | @@ -5507,6 +5864,7 @@ summary | System.Net.Sockets;MulticastOption;false;set_LocalAddress;(System.Net.IPAddress);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;NetworkStream;false;BeginRead;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Sockets;NetworkStream;false;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | +| System.Net.Sockets;NetworkStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;NetworkStream;false;NetworkStream;(System.Net.Sockets.Socket,System.IO.FileAccess,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;NetworkStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.Net.Sockets;NetworkStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | @@ -5520,6 +5878,7 @@ summary | System.Net.Sockets;NetworkStream;false;get_Socket;();;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;SafeSocketHandle;false;SafeSocketHandle;(System.IntPtr,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;Accept;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | @@ -5543,6 +5902,7 @@ summary | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);;Argument[this];Argument[0];taint;generated | +| System.Net.Sockets;Socket;false;EndAccept;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | @@ -5559,6 +5919,7 @@ summary | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.EndPoint);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | @@ -5568,6 +5929,7 @@ summary | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[4];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | @@ -5615,6 +5977,7 @@ summary | System.Net.Sockets;SocketAsyncEventArgs;false;set_SendPacketsElements;(System.Net.Sockets.SendPacketsElement[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Sockets;SocketAsyncEventArgs;false;set_UserToken;(System.Object);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;SocketException;false;get_Message;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint);;Argument[1];Argument[0];taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated | @@ -5626,6 +5989,8 @@ summary | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendToAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];Argument[0];taint;generated | @@ -5640,6 +6005,8 @@ summary | System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;AcceptTcpClient;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;TcpListener;false;EndAcceptSocket;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net.Sockets;TcpListener;false;EndAcceptTcpClient;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPAddress,System.Int32);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPEndPoint);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;TcpListener;false;get_LocalEndpoint;();;Argument[this];ReturnValue;taint;generated | @@ -5721,6 +6088,7 @@ summary | System.Net;Cookie;false;set_Value;(System.String);;Argument[0];Argument[this];taint;generated | | System.Net;CookieCollection;false;Add;(System.Net.Cookie);;Argument[0];Argument[this].Element;value;manual | | System.Net;CookieCollection;false;Add;(System.Net.CookieCollection);;Argument[0];Argument[this].Element;value;manual | +| System.Net;CookieCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net;CookieCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net;CookieCollection;false;CopyTo;(System.Net.Cookie[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net;CookieCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -5731,11 +6099,17 @@ summary | System.Net;CookieException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | | System.Net;CredentialCache;false;GetCredential;(System.Uri,System.String);;Argument[this];ReturnValue;taint;generated | | System.Net;CredentialCache;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Net;Dns;false;EndGetHostAddresses;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndGetHostByName;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndGetHostEntry;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndResolve;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;DnsEndPoint;false;DnsEndPoint;(System.String,System.Int32,System.Net.Sockets.AddressFamily);;Argument[0];Argument[this];taint;generated | | System.Net;DnsEndPoint;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.Net;DnsEndPoint;false;get_Host;();;Argument[this];ReturnValue;taint;generated | | System.Net;DownloadDataCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated | | System.Net;DownloadStringCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated | +| System.Net;FileWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;FileWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;get_ContentType;();;Argument[this];ReturnValue;taint;generated | @@ -5782,6 +6156,7 @@ summary | System.Net;HttpListenerContext;false;get_Response;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpListenerContext;false;get_User;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpListenerPrefixCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | +| System.Net;HttpListenerPrefixCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net;HttpListenerPrefixCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net;HttpListenerPrefixCollection;false;CopyTo;(System.String[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Net;HttpListenerPrefixCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -5814,6 +6189,9 @@ summary | System.Net;HttpListenerTimeoutManager;false;get_IdleConnection;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpListenerTimeoutManager;false;set_DrainEntityBody;(System.TimeSpan);;Argument[0];Argument[this];taint;generated | | System.Net;HttpListenerTimeoutManager;false;set_IdleConnection;(System.TimeSpan);;Argument[0];Argument[this];taint;generated | +| System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | +| System.Net;HttpWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetRequestStream;(System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated | @@ -5899,6 +6277,8 @@ summary | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest);;Argument[0];ReturnValue;taint;generated | | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];Argument[this];taint;generated | | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];Argument[this];taint;generated | +| System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];ReturnValue;taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];Argument[this];taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -6019,6 +6399,7 @@ summary | System.Net;WebException;false;WebException;(System.String,System.Exception,System.Net.WebExceptionStatus,System.Net.WebResponse);;Argument[3];Argument[this];taint;generated | | System.Net;WebException;false;get_Response;();;Argument[this];ReturnValue;taint;generated | | System.Net;WebHeaderCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | +| System.Net;WebHeaderCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net;WebHeaderCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Net;WebHeaderCollection;false;ToByteArray;();;Argument[this];ReturnValue;taint;generated | | System.Net;WebHeaderCollection;false;ToString;();;Argument[this];ReturnValue;taint;generated | @@ -6046,7 +6427,6 @@ summary | System.Numerics;BigInteger;false;Max;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated | -| System.Numerics;BigInteger;false;Negate;(System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Pow;(System.Numerics.BigInteger,System.Int32);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Remainder;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;Complex;false;ToString;(System.IFormatProvider);;Argument[0];ReturnValue;taint;generated | @@ -6834,9 +7214,11 @@ summary | System.Resources;ResourceReader;false;GetResourceData;(System.String,System.String,System.Byte[]);;Argument[this];ReturnValue;taint;generated | | System.Resources;ResourceReader;false;ResourceReader;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | | System.Resources;ResourceSet;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Resources;ResourceSet;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Resources;ResourceSet;false;ResourceSet;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | | System.Resources;ResourceSet;false;ResourceSet;(System.Resources.IResourceReader);;Argument[0].Element;Argument[this];taint;generated | | System.Resources;ResourceWriter;false;ResourceWriter;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | +| System.Resources;ResourceWriter;false;ResourceWriter;(System.String);;Argument[0];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncIteratorMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncIteratorMethodBuilder;false;AwaitUnsafeOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncTaskMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | @@ -6853,6 +7235,7 @@ summary | System.Runtime.CompilerServices;AsyncValueTaskMethodBuilder<>;false;SetResult;(TResult);;Argument[0];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncValueTaskMethodBuilder<>;false;get_Task;();;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;CallSite;false;get_Binder;();;Argument[this];ReturnValue;taint;generated | +| System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetOrCreateValue;(TKey);;Argument[0];ReturnValue;taint;generated | @@ -6872,8 +7255,6 @@ summary | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider);;Argument[2];Argument[this];taint;generated | | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[2];Argument[this];taint;generated | | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[3];Argument[this];taint;generated | -| System.Runtime.CompilerServices;DynamicAttribute;false;DynamicAttribute;(System.Boolean[]);;Argument[0].Element;Argument[this];taint;generated | -| System.Runtime.CompilerServices;DynamicAttribute;false;get_TransformFlags;();;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[0];ReturnValue;taint;generated | | System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[1].Element;ReturnValue;taint;generated | | System.Runtime.CompilerServices;PoolingAsyncValueTaskMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | @@ -6884,6 +7265,7 @@ summary | System.Runtime.CompilerServices;PoolingAsyncValueTaskMethodBuilder<>;false;get_Task;();;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -7237,6 +7619,7 @@ summary | System.Security.Cryptography.X509Certificates;X509Certificate;false;ToString;(System.Boolean);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Issuer;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Subject;();;Argument[this];ReturnValue;taint;generated | +| System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;Add;(System.Security.Cryptography.X509Certificates.X509Certificate);;Argument[0];Argument[this].Element;value;manual | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this].Element;value;manual | @@ -7370,6 +7753,7 @@ summary | System.Security.Cryptography.Xml;EncryptionProperty;false;set_PropertyElement;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;Add;(System.Security.Cryptography.Xml.EncryptionProperty);;Argument[0];Argument[this];taint;generated | +| System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;CopyTo;(System.Security.Cryptography.Xml.EncryptionProperty[],System.Int32);;Argument[this];Argument[0].Element;taint;generated | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -7383,6 +7767,7 @@ summary | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;set_ItemOf;(System.Int32,System.Security.Cryptography.Xml.EncryptionProperty);;Argument[1];Argument[this];taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;AddClause;(System.Security.Cryptography.Xml.KeyInfoClause);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | +| System.Security.Cryptography.Xml;KeyInfo;false;GetEnumerator;(System.Type);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;LoadXml;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;get_Id;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;set_Id;(System.String);;Argument[0];Argument[this];taint;generated | @@ -7438,6 +7823,7 @@ summary | System.Security.Cryptography.Xml;Reference;false;set_Type;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;Reference;false;set_Uri;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;ReferenceList;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.Security.Cryptography.Xml;ReferenceList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Security.Cryptography.Xml;ReferenceList;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Security.Cryptography.Xml;ReferenceList;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Security.Cryptography.Xml;ReferenceList;false;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | @@ -7502,6 +7888,7 @@ summary | System.Security.Cryptography.Xml;Transform;false;set_Context;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.Xml;Transform;false;set_Resolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;TransformChain;false;Add;(System.Security.Cryptography.Xml.Transform);;Argument[0];Argument[this];taint;generated | +| System.Security.Cryptography.Xml;TransformChain;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;TransformChain;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;XmlDecryptionTransform;false;AddExceptUri;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;XmlDecryptionTransform;false;GetOutput;();;Argument[this];ReturnValue;taint;generated | @@ -7576,10 +7963,13 @@ summary | System.Security.Cryptography;CryptoStream;false;CryptoStream;(System.IO.Stream,System.Security.Cryptography.ICryptoTransform,System.Security.Cryptography.CryptoStreamMode,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;CryptoStream;false;CryptoStream;(System.IO.Stream,System.Security.Cryptography.ICryptoTransform,System.Security.Cryptography.CryptoStreamMode,System.Boolean);;Argument[1];Argument[this];taint;generated | | System.Security.Cryptography;CryptoStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Security.Cryptography;CryptoStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography;CryptoStream;false;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.Security.Cryptography;CryptoStream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.Security.Cryptography;CryptoStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography;CryptoStream;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.Security.Cryptography;CryptoStream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.Security.Cryptography;CryptoStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography;CspParameters;false;get_ParentWindowHandle;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography;CspParameters;false;set_ParentWindowHandle;(System.IntPtr);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;DSASignatureDeformatter;false;DSASignatureDeformatter;(System.Security.Cryptography.AsymmetricAlgorithm);;Argument[0];Argument[this];taint;generated | @@ -7646,6 +8036,7 @@ summary | System.Security.Cryptography;RSAPKCS1SignatureFormatter;false;SetHashAlgorithm;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;RSAPKCS1SignatureFormatter;false;SetKey;(System.Security.Cryptography.AsymmetricAlgorithm);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;SafeEvpPKeyHandle;false;DuplicateHandle;();;Argument[this];ReturnValue;taint;generated | +| System.Security.Policy;Evidence;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Security.Policy;Evidence;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Security.Policy;Evidence;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Security.Principal;GenericIdentity;false;Clone;();;Argument[this];ReturnValue;taint;generated | @@ -7659,6 +8050,7 @@ summary | System.Security.Principal;GenericPrincipal;false;GenericPrincipal;(System.Security.Principal.IIdentity,System.String[]);;Argument[0];Argument[this];taint;generated | | System.Security.Principal;GenericPrincipal;false;get_Identity;();;Argument[this];ReturnValue;taint;generated | | System.Security.Principal;IdentityReferenceCollection;false;Add;(System.Security.Principal.IdentityReference);;Argument[0];Argument[this].Element;value;manual | +| System.Security.Principal;IdentityReferenceCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Security.Principal;IdentityReferenceCollection;false;CopyTo;(System.Security.Principal.IdentityReference[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Security.Principal;IdentityReferenceCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System.Security.Principal;IdentityReferenceCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -7690,6 +8082,8 @@ summary | System.Text.Encodings.Web;TextEncoder;true;Encode;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Text.Json.Nodes;JsonArray;false;Add;(System.Text.Json.Nodes.JsonNode);;Argument[0];Argument[this].Element;value;manual | | System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[0];Argument[this];taint;generated | +| System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[this];Argument[0];taint;generated | +| System.Text.Json.Nodes;JsonArray;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text.Json.Nodes;JsonArray;false;CopyTo;(System.Text.Json.Nodes.JsonNode[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.Json.Nodes;JsonArray;false;Create;(System.Text.Json.JsonElement,System.Nullable);;Argument[0];ReturnValue;taint;generated | | System.Text.Json.Nodes;JsonArray;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -7713,6 +8107,7 @@ summary | System.Text.Json.Nodes;JsonObject;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0];Argument[this].Element;value;manual | | System.Text.Json.Nodes;JsonObject;false;Add;(System.String,System.Text.Json.Nodes.JsonNode);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Text.Json.Nodes;JsonObject;false;Add;(System.String,System.Text.Json.Nodes.JsonNode);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Text.Json.Nodes;JsonObject;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text.Json.Nodes;JsonObject;false;CopyTo;(System.Collections.Generic.KeyValuePair[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.Json.Nodes;JsonObject;false;Create;(System.Text.Json.JsonElement,System.Nullable);;Argument[0];ReturnValue;taint;generated | | System.Text.Json.Nodes;JsonObject;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -7788,6 +8183,7 @@ summary | System.Text.Json;Utf8JsonWriter;false;get_Options;();;Argument[this];ReturnValue;taint;generated | | System.Text.RegularExpressions;CaptureCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Text.RegularExpressions;CaptureCollection;false;Add;(System.Text.RegularExpressions.Capture);;Argument[0];Argument[this].Element;value;manual | +| System.Text.RegularExpressions;CaptureCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text.RegularExpressions;CaptureCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;CaptureCollection;false;CopyTo;(System.Text.RegularExpressions.Capture[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;CaptureCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -7801,6 +8197,7 @@ summary | System.Text.RegularExpressions;Group;false;Synchronized;(System.Text.RegularExpressions.Group);;Argument[0];ReturnValue;taint;generated | | System.Text.RegularExpressions;GroupCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Text.RegularExpressions;GroupCollection;false;Add;(System.Text.RegularExpressions.Group);;Argument[0];Argument[this].Element;value;manual | +| System.Text.RegularExpressions;GroupCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text.RegularExpressions;GroupCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;GroupCollection;false;CopyTo;(System.Text.RegularExpressions.Group[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;GroupCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -7818,6 +8215,7 @@ summary | System.Text.RegularExpressions;Match;false;Synchronized;(System.Text.RegularExpressions.Match);;Argument[0];ReturnValue;taint;generated | | System.Text.RegularExpressions;MatchCollection;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System.Text.RegularExpressions;MatchCollection;false;Add;(System.Text.RegularExpressions.Match);;Argument[0];Argument[this].Element;value;manual | +| System.Text.RegularExpressions;MatchCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text.RegularExpressions;MatchCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;MatchCollection;false;CopyTo;(System.Text.RegularExpressions.Match[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Text.RegularExpressions;MatchCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | @@ -8047,6 +8445,7 @@ summary | System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[0];Argument[this].Element;value;manual | | System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[this];ReturnValue;value;manual | | System.Text;StringBuilder;false;AppendLine;(System.Text.StringBuilder+AppendInterpolatedStringHandler);;Argument[this];ReturnValue;taint;generated | +| System.Text;StringBuilder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text;StringBuilder;false;GetChunks;();;Argument[this];ReturnValue;taint;generated | | System.Text;StringBuilder;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | | System.Text;StringBuilder;false;Insert;(System.Int32,System.Boolean);;Argument[this];ReturnValue;taint;generated | @@ -8154,6 +8553,10 @@ summary | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock,TInput,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;TryReceive<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock,TOutput);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlockOptions;false;get_CancellationToken;();;Argument[this];ReturnValue;taint;generated | @@ -8717,6 +9120,7 @@ summary | System.Xml.Linq;XText;false;XText;(System.Xml.Linq.XText);;Argument[0];Argument[this];taint;generated | | System.Xml.Linq;XText;false;get_Value;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Linq;XText;false;set_Value;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Xml.Resolvers;XmlPreloadedResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;XmlPreloadedResolver;(System.Xml.XmlResolver,System.Xml.Resolvers.XmlKnownDtds,System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | @@ -8949,9 +9353,12 @@ summary | System.Xml.Schema;XmlSchemaSet;false;Add;(System.String,System.Xml.XmlReader);;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchemaSet);;Argument[0];Argument[this];taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);;Argument[this];Argument[0].Element;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Remove;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;Schemas;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;XmlSchemaSet;(System.Xml.XmlNameTable);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;get_CompilationSettings;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;get_GlobalAttributes;();;Argument[this];ReturnValue;taint;generated | @@ -9038,8 +9445,10 @@ summary | System.Xml.Schema;XmlSchemaXPath;false;get_XPath;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaXPath;false;set_XPath;(System.String);;Argument[0];Argument[this];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[this];Argument[1];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[0];ReturnValue;taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[this];Argument[1];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;MakeUnique;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;ToArray;(System.Type);;Argument[this];ReturnValue;taint;generated | | System.Xml.Serialization;ImportContext;false;ImportContext;(System.Xml.Serialization.CodeIdentifiers,System.Boolean);;Argument[0];Argument[this];taint;generated | @@ -9346,6 +9755,7 @@ summary | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.Xml.XmlQualifiedName);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteId;(System.Object);;Argument[this];Argument[0];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncoded;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.Byte[],System.Xml.XmlQualifiedName);;Argument[2].Element;Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | @@ -9353,9 +9763,15 @@ summary | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.Byte[]);;Argument[2].Element;Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[this];Argument[2];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[0];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteSerializable;(System.Xml.Serialization.IXmlSerializable,System.String,System.String,System.Boolean);;Argument[0];Argument[this];taint;generated | @@ -10061,6 +10477,7 @@ summary | System.Xml;XmlReaderSettings;false;set_XmlResolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated | +| System.Xml;XmlSecureResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlSecureResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlSecureResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlSecureResolver;false;XmlSecureResolver;(System.Xml.XmlResolver,System.String);;Argument[0];Argument[this];taint;generated | @@ -10107,6 +10524,7 @@ summary | System.Xml;XmlTextWriter;false;XmlTextWriter;(System.IO.TextWriter);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlTextWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.Xml;XmlTextWriter;false;get_XmlLang;();;Argument[this];ReturnValue;taint;generated | +| System.Xml;XmlUrlResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlUrlResolver;false;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlUrlResolver;false;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlUrlResolver;false;set_Credentials;(System.Net.ICredentials);;Argument[0];Argument[this];taint;generated | @@ -10134,6 +10552,8 @@ summary | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | +| System.Xml;XmlWriter;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.Text.StringBuilder,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.Xml.XmlWriter);;Argument[0];ReturnValue;taint;generated | @@ -10188,6 +10608,9 @@ summary | System;ArgumentOutOfRangeException;false;get_Message;();;Argument[this];ReturnValue;taint;generated | | System;Array;false;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | | System;Array;false;AsReadOnly<>;(T[]);;Argument[0].Element;ReturnValue.Element;value;manual | +| System;Array;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System;Array;false;Clear;(System.Array);;Argument[0].WithoutElement;Argument[0];value;manual | +| System;Array;false;Clear;(System.Array,System.Int32,System.Int32);;Argument[0].WithoutElement;Argument[0];value;manual | | System;Array;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System;Array;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System;Array;false;CopyTo;(System.Array,System.Int64);;Argument[this].Element;Argument[0].Element;value;manual | @@ -10212,6 +10635,7 @@ summary | System;ArraySegment<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | | System;ArraySegment<>;false;ArraySegment;(T[]);;Argument[0].Element;Argument[this];taint;generated | | System;ArraySegment<>;false;ArraySegment;(T[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | +| System;ArraySegment<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System;ArraySegment<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System;ArraySegment<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.IEnumerator<>.Current];value;manual | | System;ArraySegment<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -11223,6 +11647,27 @@ summary | System;TupleExtensions;false;Deconstruct<,>;(System.Tuple,T1,T2);;Argument[0].Property[System.Tuple<,>.Item1];Argument[1];value;manual | | System;TupleExtensions;false;Deconstruct<,>;(System.Tuple,T1,T2);;Argument[0].Property[System.Tuple<,>.Item2];Argument[2];value;manual | | System;TupleExtensions;false;Deconstruct<>;(System.Tuple,T1);;Argument[0].Property[System.Tuple<>.Item1];Argument[1];value;manual | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | @@ -13397,7 +13842,6 @@ negativeSummary | System.CodeDom.Compiler;IndentedTextWriter;Close;();generated | | System.CodeDom.Compiler;IndentedTextWriter;DisposeAsync;();generated | | System.CodeDom.Compiler;IndentedTextWriter;Flush;();generated | -| System.CodeDom.Compiler;IndentedTextWriter;FlushAsync;();generated | | System.CodeDom.Compiler;IndentedTextWriter;IndentedTextWriter;(System.IO.TextWriter);generated | | System.CodeDom.Compiler;IndentedTextWriter;OutputTabs;();generated | | System.CodeDom.Compiler;IndentedTextWriter;OutputTabsAsync;();generated | @@ -13441,7 +13885,6 @@ negativeSummary | System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.String);generated | | System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);generated | | System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabs;(System.String);generated | -| System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabsAsync;(System.String);generated | | System.CodeDom.Compiler;IndentedTextWriter;get_Indent;();generated | | System.CodeDom.Compiler;IndentedTextWriter;set_Indent;(System.Int32);generated | | System.Collections.Concurrent;BlockingCollection<>;AddToAny;(System.Collections.Concurrent.BlockingCollection<>[],T);generated | @@ -13491,7 +13934,6 @@ negativeSummary | System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair);generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Object);generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;ContainsKey;(TKey);generated | -| System.Collections.Concurrent;ConcurrentDictionary<,>;GetEnumerator;();generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Collections.Generic.KeyValuePair);generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Object);generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(TKey);generated | @@ -13549,7 +13991,6 @@ negativeSummary | System.Collections.Concurrent;Partitioner<>;GetPartitions;(System.Int32);generated | | System.Collections.Concurrent;Partitioner<>;get_SupportsDynamicPartitions;();generated | | System.Collections.Generic;CollectionExtensions;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey);generated | -| System.Collections.Generic;CollectionExtensions;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);generated | | System.Collections.Generic;Comparer<>;Compare;(System.Object,System.Object);generated | | System.Collections.Generic;Comparer<>;Compare;(T,T);generated | | System.Collections.Generic;Comparer<>;get_Default;();generated | @@ -13677,7 +14118,6 @@ negativeSummary | System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | | System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String);generated | | System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String,System.Exception);generated | -| System.Collections.Generic;KeyValuePair;Create<,>;(TKey,TValue);generated | | System.Collections.Generic;KeyValuePair<,>;ToString;();generated | | System.Collections.Generic;LinkedList<>+Enumerator;Dispose;();generated | | System.Collections.Generic;LinkedList<>+Enumerator;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | @@ -13985,9 +14425,6 @@ negativeSummary | System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;();generated | | System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer);generated | | System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);generated | -| System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable>);generated | -| System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated | -| System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated | | System.Collections.Immutable;ImmutableDictionary;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary,TKey);generated | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;Clear;();generated | | System.Collections.Immutable;ImmutableDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair);generated | @@ -14077,10 +14514,8 @@ negativeSummary | System.Collections.Immutable;ImmutableInterlocked;TryRemove<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue);generated | | System.Collections.Immutable;ImmutableInterlocked;TryUpdate<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue,TValue);generated | | System.Collections.Immutable;ImmutableList;Create<>;();generated | -| System.Collections.Immutable;ImmutableList;Create<>;(T);generated | | System.Collections.Immutable;ImmutableList;Create<>;(T[]);generated | | System.Collections.Immutable;ImmutableList;CreateBuilder<>;();generated | -| System.Collections.Immutable;ImmutableList;CreateRange<>;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T);generated | | System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T,System.Collections.Generic.IEqualityComparer);generated | | System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList,T,System.Int32);generated | @@ -14144,9 +14579,6 @@ negativeSummary | System.Collections.Immutable;ImmutableQueue<>;get_IsEmpty;();generated | | System.Collections.Immutable;ImmutableSortedDictionary;Create<,>;();generated | | System.Collections.Immutable;ImmutableSortedDictionary;CreateBuilder<,>;();generated | -| System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);generated | -| System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);generated | -| System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable>);generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Clear;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair);generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Object);generated | @@ -14166,7 +14598,6 @@ negativeSummary | System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Dispose;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;MoveNext;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Reset;();generated | -| System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;get_Current;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;Clear;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair);generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Object);generated | @@ -14183,8 +14614,6 @@ negativeSummary | System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsReadOnly;();generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsSynchronized;();generated | | System.Collections.Immutable;ImmutableSortedSet;Create<>;();generated | -| System.Collections.Immutable;ImmutableSortedSet;Create<>;(System.Collections.Generic.IComparer,T);generated | -| System.Collections.Immutable;ImmutableSortedSet;Create<>;(T);generated | | System.Collections.Immutable;ImmutableSortedSet;Create<>;(T[]);generated | | System.Collections.Immutable;ImmutableSortedSet;CreateBuilder<>;();generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;Clear;();generated | @@ -14198,7 +14627,6 @@ negativeSummary | System.Collections.Immutable;ImmutableSortedSet<>+Builder;Overlaps;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;Remove;(T);generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;SetEquals;(System.Collections.Generic.IEnumerable);generated | -| System.Collections.Immutable;ImmutableSortedSet<>+Builder;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_Count;();generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsReadOnly;();generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsSynchronized;();generated | @@ -14212,7 +14640,6 @@ negativeSummary | System.Collections.Immutable;ImmutableSortedSet<>;ExceptWith;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(System.Object);generated | | System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(T);generated | -| System.Collections.Immutable;ImmutableSortedSet<>;Intersect;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;IntersectWith;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;IsProperSubsetOf;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;IsProperSupersetOf;(System.Collections.Generic.IEnumerable);generated | @@ -14224,7 +14651,6 @@ negativeSummary | System.Collections.Immutable;ImmutableSortedSet<>;Remove;(T);generated | | System.Collections.Immutable;ImmutableSortedSet<>;RemoveAt;(System.Int32);generated | | System.Collections.Immutable;ImmutableSortedSet<>;SetEquals;(System.Collections.Generic.IEnumerable);generated | -| System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExcept;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;UnionWith;(System.Collections.Generic.IEnumerable);generated | | System.Collections.Immutable;ImmutableSortedSet<>;get_Count;();generated | @@ -15889,7 +16315,6 @@ negativeSummary | System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_ComponentType;();generated | | System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_IsReadOnly;();generated | | System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_PropertyType;();generated | -| System.ComponentModel;TypeConverter+StandardValuesCollection;GetEnumerator;();generated | | System.ComponentModel;TypeConverter+StandardValuesCollection;get_Count;();generated | | System.ComponentModel;TypeConverter+StandardValuesCollection;get_IsSynchronized;();generated | | System.ComponentModel;TypeConverter+StandardValuesCollection;get_SyncRoot;();generated | @@ -16172,14 +16597,9 @@ negativeSummary | System.Data.Common;DbCommand;DbCommand;();generated | | System.Data.Common;DbCommand;DisposeAsync;();generated | | System.Data.Common;DbCommand;ExecuteDbDataReader;(System.Data.CommandBehavior);generated | -| System.Data.Common;DbCommand;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated | | System.Data.Common;DbCommand;ExecuteNonQuery;();generated | | System.Data.Common;DbCommand;ExecuteNonQueryAsync;();generated | | System.Data.Common;DbCommand;ExecuteNonQueryAsync;(System.Threading.CancellationToken);generated | -| System.Data.Common;DbCommand;ExecuteReaderAsync;();generated | -| System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior);generated | -| System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated | -| System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Threading.CancellationToken);generated | | System.Data.Common;DbCommand;ExecuteScalar;();generated | | System.Data.Common;DbCommand;ExecuteScalarAsync;();generated | | System.Data.Common;DbCommand;ExecuteScalarAsync;(System.Threading.CancellationToken);generated | @@ -16263,7 +16683,6 @@ negativeSummary | System.Data.Common;DbConnectionStringBuilder;GetDefaultEvent;();generated | | System.Data.Common;DbConnectionStringBuilder;GetDefaultProperty;();generated | | System.Data.Common;DbConnectionStringBuilder;GetEditor;(System.Type);generated | -| System.Data.Common;DbConnectionStringBuilder;GetEnumerator;();generated | | System.Data.Common;DbConnectionStringBuilder;GetEvents;();generated | | System.Data.Common;DbConnectionStringBuilder;GetEvents;(System.Attribute[]);generated | | System.Data.Common;DbConnectionStringBuilder;GetProperties;(System.Collections.Hashtable);generated | @@ -16331,8 +16750,6 @@ negativeSummary | System.Data.Common;DbDataReader;GetDecimal;(System.Int32);generated | | System.Data.Common;DbDataReader;GetDouble;(System.Int32);generated | | System.Data.Common;DbDataReader;GetFieldType;(System.Int32);generated | -| System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32);generated | -| System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);generated | | System.Data.Common;DbDataReader;GetFloat;(System.Int32);generated | | System.Data.Common;DbDataReader;GetGuid;(System.Int32);generated | | System.Data.Common;DbDataReader;GetInt16;(System.Int32);generated | @@ -16342,7 +16759,6 @@ negativeSummary | System.Data.Common;DbDataReader;GetOrdinal;(System.String);generated | | System.Data.Common;DbDataReader;GetProviderSpecificFieldType;(System.Int32);generated | | System.Data.Common;DbDataReader;GetSchemaTable;();generated | -| System.Data.Common;DbDataReader;GetSchemaTableAsync;(System.Threading.CancellationToken);generated | | System.Data.Common;DbDataReader;GetStream;(System.Int32);generated | | System.Data.Common;DbDataReader;GetString;(System.Int32);generated | | System.Data.Common;DbDataReader;GetValue;(System.Int32);generated | @@ -17057,9 +17473,6 @@ negativeSummary | System.Data;DataColumnChangeEventArgs;get_ProposedValue;();generated | | System.Data;DataColumnChangeEventArgs;get_Row;();generated | | System.Data;DataColumnChangeEventArgs;set_ProposedValue;(System.Object);generated | -| System.Data;DataColumnCollection;Add;();generated | -| System.Data;DataColumnCollection;Add;(System.String,System.Type);generated | -| System.Data;DataColumnCollection;Add;(System.String,System.Type,System.String);generated | | System.Data;DataColumnCollection;CanRemove;(System.Data.DataColumn);generated | | System.Data;DataColumnCollection;Clear;();generated | | System.Data;DataColumnCollection;Contains;(System.String);generated | @@ -17082,7 +17495,6 @@ negativeSummary | System.Data;DataReaderExtensions;GetDecimal;(System.Data.Common.DbDataReader,System.String);generated | | System.Data;DataReaderExtensions;GetDouble;(System.Data.Common.DbDataReader,System.String);generated | | System.Data;DataReaderExtensions;GetFieldType;(System.Data.Common.DbDataReader,System.String);generated | -| System.Data;DataReaderExtensions;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);generated | | System.Data;DataReaderExtensions;GetFloat;(System.Data.Common.DbDataReader,System.String);generated | | System.Data;DataReaderExtensions;GetInt16;(System.Data.Common.DbDataReader,System.String);generated | | System.Data;DataReaderExtensions;GetInt32;(System.Data.Common.DbDataReader,System.String);generated | @@ -17100,10 +17512,6 @@ negativeSummary | System.Data;DataRelation;get_Nested;();generated | | System.Data;DataRelation;get_ParentTable;();generated | | System.Data;DataRelation;set_Nested;(System.Boolean);generated | -| System.Data;DataRelationCollection;Add;(System.Data.DataColumn,System.Data.DataColumn);generated | -| System.Data;DataRelationCollection;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);generated | -| System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);generated | -| System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);generated | | System.Data;DataRelationCollection;AddCore;(System.Data.DataRelation);generated | | System.Data;DataRelationCollection;CanRemove;(System.Data.DataRelation);generated | | System.Data;DataRelationCollection;Clear;();generated | @@ -17356,7 +17764,6 @@ negativeSummary | System.Data;DataTableClearEventArgs;get_Table;();generated | | System.Data;DataTableClearEventArgs;get_TableName;();generated | | System.Data;DataTableClearEventArgs;get_TableNamespace;();generated | -| System.Data;DataTableCollection;Add;();generated | | System.Data;DataTableCollection;CanRemove;(System.Data.DataTable);generated | | System.Data;DataTableCollection;Clear;();generated | | System.Data;DataTableCollection;Contains;(System.String);generated | @@ -20258,12 +20665,10 @@ negativeSummary | System.IO.Compression;DeflateStream;EndWrite;(System.IAsyncResult);generated | | System.IO.Compression;DeflateStream;Flush;();generated | | System.IO.Compression;DeflateStream;Read;(System.Span);generated | -| System.IO.Compression;DeflateStream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated | | System.IO.Compression;DeflateStream;ReadByte;();generated | | System.IO.Compression;DeflateStream;Seek;(System.Int64,System.IO.SeekOrigin);generated | | System.IO.Compression;DeflateStream;SetLength;(System.Int64);generated | | System.IO.Compression;DeflateStream;Write;(System.ReadOnlySpan);generated | -| System.IO.Compression;DeflateStream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated | | System.IO.Compression;DeflateStream;get_CanRead;();generated | | System.IO.Compression;DeflateStream;get_CanSeek;();generated | | System.IO.Compression;DeflateStream;get_CanWrite;();generated | @@ -20278,12 +20683,10 @@ negativeSummary | System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel);generated | | System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode);generated | | System.IO.Compression;GZipStream;Read;(System.Span);generated | -| System.IO.Compression;GZipStream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated | | System.IO.Compression;GZipStream;ReadByte;();generated | | System.IO.Compression;GZipStream;Seek;(System.Int64,System.IO.SeekOrigin);generated | | System.IO.Compression;GZipStream;SetLength;(System.Int64);generated | | System.IO.Compression;GZipStream;Write;(System.ReadOnlySpan);generated | -| System.IO.Compression;GZipStream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated | | System.IO.Compression;GZipStream;get_CanRead;();generated | | System.IO.Compression;GZipStream;get_CanSeek;();generated | | System.IO.Compression;GZipStream;get_CanWrite;();generated | @@ -20658,7 +21061,6 @@ negativeSummary | System.IO;BinaryWriter;Close;();generated | | System.IO;BinaryWriter;Dispose;();generated | | System.IO;BinaryWriter;Dispose;(System.Boolean);generated | -| System.IO;BinaryWriter;DisposeAsync;();generated | | System.IO;BinaryWriter;Flush;();generated | | System.IO;BinaryWriter;Seek;(System.Int32,System.IO.SeekOrigin);generated | | System.IO;BinaryWriter;Write7BitEncodedInt64;(System.Int64);generated | @@ -21052,18 +21454,14 @@ negativeSummary | System.IO;Stream;EndRead;(System.IAsyncResult);generated | | System.IO;Stream;EndWrite;(System.IAsyncResult);generated | | System.IO;Stream;Flush;();generated | -| System.IO;Stream;FlushAsync;();generated | -| System.IO;Stream;FlushAsync;(System.Threading.CancellationToken);generated | | System.IO;Stream;ObjectInvariant;();generated | | System.IO;Stream;Read;(System.Span);generated | -| System.IO;Stream;ReadAsync;(System.Memory,System.Threading.CancellationToken);generated | | System.IO;Stream;ReadByte;();generated | | System.IO;Stream;Seek;(System.Int64,System.IO.SeekOrigin);generated | | System.IO;Stream;SetLength;(System.Int64);generated | | System.IO;Stream;ValidateBufferArguments;(System.Byte[],System.Int32,System.Int32);generated | | System.IO;Stream;ValidateCopyToArguments;(System.IO.Stream,System.Int32);generated | | System.IO;Stream;Write;(System.ReadOnlySpan);generated | -| System.IO;Stream;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);generated | | System.IO;Stream;WriteByte;(System.Byte);generated | | System.IO;Stream;get_CanRead;();generated | | System.IO;Stream;get_CanSeek;();generated | @@ -21085,7 +21483,6 @@ negativeSummary | System.IO;StreamWriter;Dispose;(System.Boolean);generated | | System.IO;StreamWriter;DisposeAsync;();generated | | System.IO;StreamWriter;Flush;();generated | -| System.IO;StreamWriter;FlushAsync;();generated | | System.IO;StreamWriter;StreamWriter;(System.IO.Stream);generated | | System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding);generated | | System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32);generated | @@ -21104,15 +21501,8 @@ negativeSummary | System.IO;StreamWriter;Write;(System.String,System.Object,System.Object);generated | | System.IO;StreamWriter;Write;(System.String,System.Object,System.Object,System.Object);generated | | System.IO;StreamWriter;Write;(System.String,System.Object[]);generated | -| System.IO;StreamWriter;WriteAsync;(System.Char);generated | -| System.IO;StreamWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated | -| System.IO;StreamWriter;WriteAsync;(System.String);generated | | System.IO;StreamWriter;WriteLine;(System.ReadOnlySpan);generated | | System.IO;StreamWriter;WriteLine;(System.String);generated | -| System.IO;StreamWriter;WriteLineAsync;();generated | -| System.IO;StreamWriter;WriteLineAsync;(System.Char);generated | -| System.IO;StreamWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated | -| System.IO;StreamWriter;WriteLineAsync;(System.String);generated | | System.IO;StreamWriter;get_AutoFlush;();generated | | System.IO;StreamWriter;set_AutoFlush;(System.Boolean);generated | | System.IO;StringReader;Close;();generated | @@ -21126,10 +21516,8 @@ negativeSummary | System.IO;StringWriter;StringWriter;(System.Text.StringBuilder);generated | | System.IO;StringWriter;Write;(System.Char);generated | | System.IO;StringWriter;Write;(System.ReadOnlySpan);generated | -| System.IO;StringWriter;Write;(System.Text.StringBuilder);generated | | System.IO;StringWriter;WriteAsync;(System.Char);generated | | System.IO;StringWriter;WriteLine;(System.ReadOnlySpan);generated | -| System.IO;StringWriter;WriteLine;(System.Text.StringBuilder);generated | | System.IO;StringWriter;WriteLineAsync;(System.Char);generated | | System.IO;StringWriter;get_Encoding;();generated | | System.IO;TextReader;Close;();generated | @@ -21142,7 +21530,6 @@ negativeSummary | System.IO;TextWriter;Dispose;(System.Boolean);generated | | System.IO;TextWriter;DisposeAsync;();generated | | System.IO;TextWriter;Flush;();generated | -| System.IO;TextWriter;FlushAsync;();generated | | System.IO;TextWriter;TextWriter;();generated | | System.IO;TextWriter;Write;(System.Boolean);generated | | System.IO;TextWriter;Write;(System.Char);generated | @@ -21157,9 +21544,6 @@ negativeSummary | System.IO;TextWriter;Write;(System.Text.StringBuilder);generated | | System.IO;TextWriter;Write;(System.UInt32);generated | | System.IO;TextWriter;Write;(System.UInt64);generated | -| System.IO;TextWriter;WriteAsync;(System.Char);generated | -| System.IO;TextWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated | -| System.IO;TextWriter;WriteAsync;(System.String);generated | | System.IO;TextWriter;WriteLine;();generated | | System.IO;TextWriter;WriteLine;(System.Boolean);generated | | System.IO;TextWriter;WriteLine;(System.Char);generated | @@ -21169,13 +21553,8 @@ negativeSummary | System.IO;TextWriter;WriteLine;(System.Int64);generated | | System.IO;TextWriter;WriteLine;(System.ReadOnlySpan);generated | | System.IO;TextWriter;WriteLine;(System.Single);generated | -| System.IO;TextWriter;WriteLine;(System.Text.StringBuilder);generated | | System.IO;TextWriter;WriteLine;(System.UInt32);generated | | System.IO;TextWriter;WriteLine;(System.UInt64);generated | -| System.IO;TextWriter;WriteLineAsync;();generated | -| System.IO;TextWriter;WriteLineAsync;(System.Char);generated | -| System.IO;TextWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated | -| System.IO;TextWriter;WriteLineAsync;(System.String);generated | | System.IO;TextWriter;get_Encoding;();generated | | System.IO;UnmanagedMemoryAccessor;Dispose;();generated | | System.IO;UnmanagedMemoryAccessor;Dispose;(System.Boolean);generated | @@ -21885,7 +22264,6 @@ negativeSummary | System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;Reset;();generated | | System.Net.Http.Headers;HttpHeadersNonValidated;Contains;(System.String);generated | | System.Net.Http.Headers;HttpHeadersNonValidated;ContainsKey;(System.String);generated | -| System.Net.Http.Headers;HttpHeadersNonValidated;GetEnumerator;();generated | | System.Net.Http.Headers;HttpHeadersNonValidated;get_Count;();generated | | System.Net.Http.Headers;HttpRequestHeaders;get_Accept;();generated | | System.Net.Http.Headers;HttpRequestHeaders;get_AcceptCharset;();generated | @@ -22068,7 +22446,6 @@ negativeSummary | System.Net.Http.Json;JsonContent;TryComputeLength;(System.Int64);generated | | System.Net.Http.Json;JsonContent;get_ObjectType;();generated | | System.Net.Http.Json;JsonContent;get_Value;();generated | -| System.Net.Http;ByteArrayContent;CreateContentReadStreamAsync;();generated | | System.Net.Http;ByteArrayContent;TryComputeLength;(System.Int64);generated | | System.Net.Http;DelegatingHandler;DelegatingHandler;();generated | | System.Net.Http;DelegatingHandler;Dispose;(System.Boolean);generated | @@ -22168,7 +22545,6 @@ negativeSummary | System.Net.Http;HttpClientHandler;set_UseDefaultCredentials;(System.Boolean);generated | | System.Net.Http;HttpClientHandler;set_UseProxy;(System.Boolean);generated | | System.Net.Http;HttpContent;CreateContentReadStreamAsync;();generated | -| System.Net.Http;HttpContent;CreateContentReadStreamAsync;(System.Threading.CancellationToken);generated | | System.Net.Http;HttpContent;Dispose;();generated | | System.Net.Http;HttpContent;Dispose;(System.Boolean);generated | | System.Net.Http;HttpContent;HttpContent;();generated | @@ -22255,7 +22631,6 @@ negativeSummary | System.Net.Http;MultipartContent;get_HeaderEncodingSelector;();generated | | System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;();generated | | System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;(System.String);generated | -| System.Net.Http;ReadOnlyMemoryContent;CreateContentReadStreamAsync;();generated | | System.Net.Http;ReadOnlyMemoryContent;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated | | System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);generated | | System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated | @@ -22697,7 +23072,6 @@ negativeSummary | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;get_Count;();generated | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;get_IsReadOnly;();generated | | System.Net.Security;AuthenticatedStream;Dispose;(System.Boolean);generated | -| System.Net.Security;AuthenticatedStream;DisposeAsync;();generated | | System.Net.Security;AuthenticatedStream;get_IsAuthenticated;();generated | | System.Net.Security;AuthenticatedStream;get_IsEncrypted;();generated | | System.Net.Security;AuthenticatedStream;get_IsMutuallyAuthenticated;();generated | @@ -22910,7 +23284,6 @@ negativeSummary | System.Net.Sockets;SendPacketsElement;get_Offset;();generated | | System.Net.Sockets;SendPacketsElement;get_OffsetLong;();generated | | System.Net.Sockets;Socket;AcceptAsync;();generated | -| System.Net.Sockets;Socket;AcceptAsync;(System.Net.Sockets.Socket);generated | | System.Net.Sockets;Socket;CancelConnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);generated | | System.Net.Sockets;Socket;Close;();generated | | System.Net.Sockets;Socket;Close;(System.Int32);generated | @@ -22925,7 +23298,6 @@ negativeSummary | System.Net.Sockets;Socket;DuplicateAndClose;(System.Int32);generated | | System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.IAsyncResult);generated | | System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.Int32,System.IAsyncResult);generated | -| System.Net.Sockets;Socket;EndAccept;(System.IAsyncResult);generated | | System.Net.Sockets;Socket;EndConnect;(System.IAsyncResult);generated | | System.Net.Sockets;Socket;EndDisconnect;(System.IAsyncResult);generated | | System.Net.Sockets;Socket;EndReceive;(System.IAsyncResult);generated | @@ -22958,8 +23330,6 @@ negativeSummary | System.Net.Sockets;Socket;Receive;(System.Span,System.Net.Sockets.SocketFlags,System.Net.Sockets.SocketError);generated | | System.Net.Sockets;Socket;ReceiveAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags);generated | | System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated | -| System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated | -| System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated | | System.Net.Sockets;Socket;Select;(System.Collections.IList,System.Collections.IList,System.Collections.IList,System.Int32);generated | | System.Net.Sockets;Socket;Send;(System.Byte[]);generated | | System.Net.Sockets;Socket;Send;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags);generated | @@ -23057,14 +23427,11 @@ negativeSummary | System.Net.Sockets;SocketInformation;set_Options;(System.Net.Sockets.SocketInformationOptions);generated | | System.Net.Sockets;SocketInformation;set_ProtocolInformation;(System.Byte[]);generated | | System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket);generated | -| System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);generated | | System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32);generated | | System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32,System.Threading.CancellationToken);generated | | System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.String,System.Int32);generated | | System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags);generated | | System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated | -| System.Net.Sockets;SocketTaskExtensions;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated | -| System.Net.Sockets;SocketTaskExtensions;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated | | System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags);generated | | System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList>,System.Net.Sockets.SocketFlags);generated | | System.Net.Sockets;TcpClient;Close;();generated | @@ -23106,8 +23473,6 @@ negativeSummary | System.Net.Sockets;TcpListener;AcceptTcpClientAsync;(System.Threading.CancellationToken);generated | | System.Net.Sockets;TcpListener;AllowNatTraversal;(System.Boolean);generated | | System.Net.Sockets;TcpListener;Create;(System.Int32);generated | -| System.Net.Sockets;TcpListener;EndAcceptSocket;(System.IAsyncResult);generated | -| System.Net.Sockets;TcpListener;EndAcceptTcpClient;(System.IAsyncResult);generated | | System.Net.Sockets;TcpListener;Pending;();generated | | System.Net.Sockets;TcpListener;Start;();generated | | System.Net.Sockets;TcpListener;Start;(System.Int32);generated | @@ -23321,10 +23686,6 @@ negativeSummary | System.Net;CredentialCache;Remove;(System.Uri,System.String);generated | | System.Net;CredentialCache;get_DefaultCredentials;();generated | | System.Net;CredentialCache;get_DefaultNetworkCredentials;();generated | -| System.Net;Dns;EndGetHostAddresses;(System.IAsyncResult);generated | -| System.Net;Dns;EndGetHostByName;(System.IAsyncResult);generated | -| System.Net;Dns;EndGetHostEntry;(System.IAsyncResult);generated | -| System.Net;Dns;EndResolve;(System.IAsyncResult);generated | | System.Net;Dns;GetHostAddresses;(System.String);generated | | System.Net;Dns;GetHostAddresses;(System.String,System.Net.Sockets.AddressFamily);generated | | System.Net;Dns;GetHostAddressesAsync;(System.String);generated | @@ -23353,8 +23714,6 @@ negativeSummary | System.Net;EndPoint;Serialize;();generated | | System.Net;EndPoint;get_AddressFamily;();generated | | System.Net;FileWebRequest;Abort;();generated | -| System.Net;FileWebRequest;EndGetRequestStream;(System.IAsyncResult);generated | -| System.Net;FileWebRequest;EndGetResponse;(System.IAsyncResult);generated | | System.Net;FileWebRequest;FileWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | | System.Net;FileWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | | System.Net;FileWebRequest;GetRequestStreamAsync;();generated | @@ -23509,9 +23868,6 @@ negativeSummary | System.Net;HttpWebRequest;AddRange;(System.String,System.Int32,System.Int32);generated | | System.Net;HttpWebRequest;AddRange;(System.String,System.Int64);generated | | System.Net;HttpWebRequest;AddRange;(System.String,System.Int64,System.Int64);generated | -| System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult);generated | -| System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);generated | -| System.Net;HttpWebRequest;EndGetResponse;(System.IAsyncResult);generated | | System.Net;HttpWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | | System.Net;HttpWebRequest;HttpWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated | | System.Net;HttpWebRequest;get_AllowAutoRedirect;();generated | @@ -23896,6 +24252,7 @@ negativeSummary | System.Numerics;BigInteger;Log;(System.Numerics.BigInteger,System.Double);generated | | System.Numerics;BigInteger;ModPow;(System.Numerics.BigInteger,System.Numerics.BigInteger,System.Numerics.BigInteger);generated | | System.Numerics;BigInteger;Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated | +| System.Numerics;BigInteger;Negate;(System.Numerics.BigInteger);generated | | System.Numerics;BigInteger;Parse;(System.ReadOnlySpan,System.Globalization.NumberStyles,System.IFormatProvider);generated | | System.Numerics;BigInteger;Parse;(System.String);generated | | System.Numerics;BigInteger;Parse;(System.String,System.Globalization.NumberStyles);generated | @@ -26582,7 +26939,6 @@ negativeSummary | System.Resources;ResourceSet;Dispose;(System.Boolean);generated | | System.Resources;ResourceSet;GetDefaultReader;();generated | | System.Resources;ResourceSet;GetDefaultWriter;();generated | -| System.Resources;ResourceSet;GetEnumerator;();generated | | System.Resources;ResourceSet;GetObject;(System.String);generated | | System.Resources;ResourceSet;GetObject;(System.String,System.Boolean);generated | | System.Resources;ResourceSet;GetString;(System.String);generated | @@ -26708,6 +27064,8 @@ negativeSummary | System.Runtime.CompilerServices;DisablePrivateReflectionAttribute;DisablePrivateReflectionAttribute;();generated | | System.Runtime.CompilerServices;DiscardableAttribute;DiscardableAttribute;();generated | | System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;();generated | +| System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;(System.Boolean[]);generated | +| System.Runtime.CompilerServices;DynamicAttribute;get_TransformFlags;();generated | | System.Runtime.CompilerServices;EnumeratorCancellationAttribute;EnumeratorCancellationAttribute;();generated | | System.Runtime.CompilerServices;FixedAddressValueTypeAttribute;FixedAddressValueTypeAttribute;();generated | | System.Runtime.CompilerServices;FixedBufferAttribute;FixedBufferAttribute;(System.Type,System.Int32);generated | @@ -32338,7 +32696,6 @@ negativeSummary | System.Security.Cryptography.X509Certificates;X509Certificate;get_Handle;();generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;MoveNext;();generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;Reset;();generated | -| System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;Contains;(System.Security.Cryptography.X509Certificates.X509Certificate);generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;GetHashCode;();generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;IndexOf;(System.Security.Cryptography.X509Certificates.X509Certificate);generated | @@ -32499,7 +32856,6 @@ negativeSummary | System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsReadOnly;();generated | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsSynchronized;();generated | | System.Security.Cryptography.Xml;IRelDecryptor;Decrypt;(System.Security.Cryptography.Xml.EncryptionMethod,System.Security.Cryptography.Xml.KeyInfo,System.IO.Stream);generated | -| System.Security.Cryptography.Xml;KeyInfo;GetEnumerator;(System.Type);generated | | System.Security.Cryptography.Xml;KeyInfo;GetXml;();generated | | System.Security.Cryptography.Xml;KeyInfo;KeyInfo;();generated | | System.Security.Cryptography.Xml;KeyInfo;get_Count;();generated | @@ -32566,7 +32922,6 @@ negativeSummary | System.Security.Cryptography.Xml;Transform;Transform;();generated | | System.Security.Cryptography.Xml;Transform;get_InputTypes;();generated | | System.Security.Cryptography.Xml;Transform;get_OutputTypes;();generated | -| System.Security.Cryptography.Xml;TransformChain;GetEnumerator;();generated | | System.Security.Cryptography.Xml;TransformChain;TransformChain;();generated | | System.Security.Cryptography.Xml;TransformChain;get_Count;();generated | | System.Security.Cryptography.Xml;XmlDecryptionTransform;GetInnerXml;();generated | @@ -35529,10 +35884,6 @@ negativeSummary | System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);generated | | System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);generated | | System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAllAsync<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock,System.Threading.CancellationToken);generated | -| System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);generated | -| System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);generated | -| System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);generated | -| System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);generated | | System.Threading.Tasks.Dataflow;DataflowBlock;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock,TInput);generated | | System.Threading.Tasks.Dataflow;DataflowBlockOptions;DataflowBlockOptions;();generated | | System.Threading.Tasks.Dataflow;DataflowBlockOptions;get_BoundedCapacity;();generated | @@ -36654,13 +37005,10 @@ negativeSummary | System.Xml.Schema;XmlSchemaParticle;set_MinOccursString;(System.String);generated | | System.Xml.Schema;XmlSchemaPatternFacet;XmlSchemaPatternFacet;();generated | | System.Xml.Schema;XmlSchemaRedefine;XmlSchemaRedefine;();generated | -| System.Xml.Schema;XmlSchemaSet;Add;(System.Xml.Schema.XmlSchemaSet);generated | | System.Xml.Schema;XmlSchemaSet;Compile;();generated | | System.Xml.Schema;XmlSchemaSet;Contains;(System.String);generated | | System.Xml.Schema;XmlSchemaSet;Contains;(System.Xml.Schema.XmlSchema);generated | -| System.Xml.Schema;XmlSchemaSet;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);generated | | System.Xml.Schema;XmlSchemaSet;RemoveRecursive;(System.Xml.Schema.XmlSchema);generated | -| System.Xml.Schema;XmlSchemaSet;Schemas;();generated | | System.Xml.Schema;XmlSchemaSet;Schemas;(System.String);generated | | System.Xml.Schema;XmlSchemaSet;XmlSchemaSet;();generated | | System.Xml.Schema;XmlSchemaSet;get_Count;();generated | @@ -36912,7 +37260,6 @@ negativeSummary | System.Xml.Serialization;XmlSerializationWriter;WriteEmptyTag;(System.String,System.String);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;();generated | | System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;(System.Object);generated | -| System.Xml.Serialization;XmlSerializationWriter;WriteId;(System.Object);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteNamespaceDeclarations;(System.Xml.Serialization.XmlSerializerNamespaces);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String,System.String);generated | @@ -36921,8 +37268,6 @@ negativeSummary | System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameEncoded;(System.String,System.String,System.Xml.XmlQualifiedName,System.Xml.XmlQualifiedName);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameLiteral;(System.String,System.String,System.Xml.XmlQualifiedName);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteReferencedElements;();generated | -| System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object);generated | -| System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteStartDocument;();generated | | System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String);generated | | System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String,System.String);generated | @@ -40382,27 +40727,6 @@ negativeSummary | System;Tuple<>;GetHashCode;();generated | | System;Tuple<>;GetHashCode;(System.Collections.IEqualityComparer);generated | | System;Tuple<>;get_Length;();generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple>>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,,>;(System.ValueTuple>);generated | -| System;TupleExtensions;ToTuple<,,,,,,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<,,,,,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<,,,,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<,,,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<,,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<,>;(System.ValueTuple);generated | -| System;TupleExtensions;ToTuple<>;(System.ValueTuple);generated | | System;Type;Equals;(System.Object);generated | | System;Type;Equals;(System.Type);generated | | System;Type;GetArrayRank;();generated | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected index d6076973c37..7f7930bef31 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected @@ -226,6 +226,7 @@ summary | Microsoft.Extensions.FileProviders.Composite;CompositeDirectoryContents;false;CompositeDirectoryContents;(System.Collections.Generic.IList,System.String);;Argument[1];Argument[this];taint;generated | | Microsoft.Extensions.FileProviders.Internal;PhysicalDirectoryContents;false;PhysicalDirectoryContents;(System.String,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalDirectoryInfo;false;PhysicalDirectoryInfo;(System.IO.DirectoryInfo);;Argument[0];Argument[this];taint;generated | +| Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;CreateReadStream;();;Argument[this];ReturnValue;taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;PhysicalFileInfo;(System.IO.FileInfo);;Argument[0];Argument[this];taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFileInfo;false;get_PhysicalPath;();;Argument[this];ReturnValue;taint;generated | | Microsoft.Extensions.FileProviders.Physical;PhysicalFilesWatcher;false;PhysicalFilesWatcher;(System.String,System.IO.FileSystemWatcher,System.Boolean,Microsoft.Extensions.FileProviders.Physical.ExclusionFilters);;Argument[0];Argument[this];taint;generated | @@ -382,6 +383,7 @@ summary | Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[0];ReturnValue;taint;manual | | Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[1];ReturnValue;taint;manual | | Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[this];ReturnValue;taint;manual | +| Microsoft.VisualBasic;Collection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | Microsoft.VisualBasic;Collection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | Microsoft.VisualBasic;Collection;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | Microsoft.VisualBasic;Collection;false;get_Item;(System.Object);;Argument[this].Element;ReturnValue;value;manual | @@ -537,6 +539,8 @@ summary | System.CodeDom.Compiler;GeneratedCodeAttribute;false;get_Version;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[0];Argument[this];taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;IndentedTextWriter;(System.IO.TextWriter,System.String);;Argument[1];Argument[this];taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.CodeDom.Compiler;IndentedTextWriter;false;WriteLineNoTabsAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;get_Encoding;();;Argument[this];ReturnValue;taint;generated | | System.CodeDom.Compiler;IndentedTextWriter;false;get_InnerWriter;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;BlockingCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | @@ -549,6 +553,7 @@ summary | System.Collections.Concurrent;BlockingCollection<>;false;TryAdd;(T,System.Int32,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.Collections.Concurrent;BlockingCollection<>;false;TryAdd;(T,System.TimeSpan);;Argument[0];Argument[this];taint;generated | | System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Concurrent;ConcurrentBag<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentBag<>;false;ToArray;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentBag<>;false;TryAdd;(T);;Argument[0];Argument[this];taint;generated | | System.Collections.Concurrent;ConcurrentBag<>;false;TryPeek;(T);;Argument[this];ReturnValue;taint;generated | @@ -561,10 +566,13 @@ summary | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Int32,System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[1].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;ConcurrentDictionary;(System.Int32,System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[1].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;GetOrAdd;(TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual | | System.Collections.Concurrent;ConcurrentDictionary<,>;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | +| System.Collections.Concurrent;ConcurrentQueue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | +| System.Collections.Concurrent;ConcurrentStack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Concurrent;ConcurrentStack<>;false;ConcurrentStack;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Concurrent;ConcurrentStack<>;false;TryPeek;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Concurrent;ConcurrentStack<>;false;TryPop;(T);;Argument[this];ReturnValue;taint;generated | @@ -581,6 +589,9 @@ summary | System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Generic;CollectionExtensions;false;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | | System.Collections.Generic;CollectionExtensions;false;Remove<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[0].Element;Argument[2];taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[1];Argument[0].Element;taint;generated | +| System.Collections.Generic;CollectionExtensions;false;TryAdd<,>;(System.Collections.Generic.IDictionary,TKey,TValue);;Argument[2];Argument[0].Element;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Entry;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Dictionary<,>+Enumerator;false;get_Key;();;Argument[this];ReturnValue;taint;generated | @@ -617,6 +628,7 @@ summary | System.Collections.Generic;HashSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;HashSet<>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;ICollection<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;ICollection<>;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;ICollection<>;true;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;IDictionary<,>;true;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;IDictionary<,>;true;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | @@ -630,6 +642,8 @@ summary | System.Collections.Generic;IList<>;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.Generic;IList<>;true;set_Item;(System.Int32,T);;Argument[1];Argument[this].Element;value;manual | | System.Collections.Generic;ISet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Generic;KeyValuePair;false;Create<,>;(TKey,TValue);;Argument[1];ReturnValue;taint;generated | | System.Collections.Generic;KeyValuePair<,>;false;Deconstruct;(TKey,TValue);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;KeyValuePair<,>;false;KeyValuePair;(TKey,TValue);;Argument[0];Argument[this].Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Generic;KeyValuePair<,>;false;KeyValuePair;(TKey,TValue);;Argument[1];Argument[this].Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | @@ -708,6 +722,7 @@ summary | System.Collections.Generic;PriorityQueue<,>;false;TryPeek;(TElement,TPriority);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;PriorityQueue<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Queue<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Generic;Queue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Queue<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Queue<>;false;Dequeue;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Queue<>;false;Enqueue;(T);;Argument[0];Argument[this];taint;generated | @@ -760,6 +775,7 @@ summary | System.Collections.Generic;SortedSet<>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;SortedSet<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Generic;Stack<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Collections.Generic;Stack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Generic;Stack<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Generic;Stack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Stack<>+Enumerator.Current];value;manual | | System.Collections.Generic;Stack<>;false;Peek;();;Argument[this].Element;ReturnValue;value;manual | @@ -771,9 +787,14 @@ summary | System.Collections.Generic;Stack<>;false;TryPop;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Generic;Stack<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableDictionary<,>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;IImmutableList<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Immutable;IImmutableList<>;true;AddRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableList<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;IImmutableQueue<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;IImmutableSet<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | +| System.Collections.Immutable;IImmutableStack<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableArray;false;Create<>;(System.Collections.Immutable.ImmutableArray,System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableArray;false;Create<>;(T,T);;Argument[0];ReturnValue;taint;generated | @@ -834,6 +855,12 @@ summary | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;Create<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableDictionary;false;CreateRange<,>;(System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary;false;ToImmutableDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IEqualityComparer);;Argument[0].Element;ReturnValue;taint;generated | @@ -861,6 +888,7 @@ summary | System.Collections.Immutable;ImmutableDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableDictionary<,>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableDictionary<,>;false;Remove;(TKey);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableDictionary<,>;false;RemoveRange;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | @@ -888,6 +916,7 @@ summary | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>+Builder;false;set_KeyComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | | System.Collections.Immutable;ImmutableHashSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual | | System.Collections.Immutable;ImmutableHashSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableHashSet<>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableHashSet<>;false;Intersect;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | @@ -901,6 +930,8 @@ summary | System.Collections.Immutable;ImmutableHashSet<>;false;get_KeyComparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableHashSet<>;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections.Immutable;ImmutableInterlocked;false;GetOrAdd<,>;(System.Collections.Immutable.ImmutableDictionary,TKey,TValue);;Argument[2];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableList;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableList;false;CreateRange<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;Remove<>;(System.Collections.Immutable.IImmutableList,T);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;RemoveRange<>;(System.Collections.Immutable.IImmutableList,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableList;false;Replace<>;(System.Collections.Immutable.IImmutableList,T,T);;Argument[0].Element;ReturnValue;taint;generated | @@ -986,6 +1017,12 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;CreateBuilder<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable>);;Argument[1].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[1];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEqualityComparer,System.Collections.Generic.IEnumerable>);;Argument[2].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary;false;CreateRange<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary;false;ToImmutableSortedDictionary<,>;(System.Collections.Generic.IEnumerable>,System.Collections.Generic.IComparer);;Argument[1];ReturnValue;taint;generated | @@ -1008,11 +1045,13 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_KeyComparer;(System.Collections.Generic.IComparer);;Argument[0];Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;false;set_ValueComparer;(System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | +| System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(System.Collections.Generic.KeyValuePair);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(TKey,TValue);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Add;(TKey,TValue);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;AddRange;(System.Collections.Generic.IEnumerable>);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableSortedDictionary<,>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;Remove;(TKey);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;RemoveRange;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | @@ -1034,7 +1073,10 @@ summary | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;get_ValueComparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedDictionary<,>;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | | System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T);;Argument[1];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(System.Collections.Generic.IComparer,T[]);;Argument[0];ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet;false;Create<>;(T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateBuilder<>;(System.Collections.Generic.IComparer);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet;false;CreateRange<>;(System.Collections.Generic.IComparer,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue;taint;generated | @@ -1046,6 +1088,7 @@ summary | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableSortedSet<>+Enumerator.Current];value;manual | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;IntersectWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;Reverse;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;SymmetricExceptWith;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;ToImmutable;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | @@ -1057,10 +1100,15 @@ summary | System.Collections.Immutable;ImmutableSortedSet<>+Builder;false;set_KeyComparer;(System.Collections.Generic.IComparer);;Argument[0];Argument[this];taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Clear;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Except;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableSortedSet<>+Enumerator.Current];value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;Intersect;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Remove;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;Reverse;();;Argument[0].Element;ReturnValue.Element;value;manual | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this];taint;generated | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;generated | +| System.Collections.Immutable;ImmutableSortedSet<>;false;SymmetricExcept;(System.Collections.Generic.IEnumerable);;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;ToBuilder;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[0];ReturnValue;taint;generated | | System.Collections.Immutable;ImmutableSortedSet<>;false;TryGetValue;(T,T);;Argument[this];ReturnValue;taint;generated | @@ -1086,18 +1134,24 @@ summary | System.Collections.Immutable;ImmutableStack<>;false;Push;(T);;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;Collection<>;false;Collection;(System.Collections.Generic.IList);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;Collection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;Collection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;Collection<>;false;get_Items;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;Collection<>;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;KeyedCollection<,>;false;InsertItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;KeyedCollection;(System.Collections.Generic.IEqualityComparer,System.Int32);;Argument[0];Argument[this];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;KeyedCollection<,>;false;SetItem;(System.Int32,TItem);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;TryGetValue;(TKey,TItem);;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Comparer;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Dictionary;();;Argument[this];ReturnValue;taint;generated | | System.Collections.ObjectModel;KeyedCollection<,>;false;get_Item;(TKey);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;ObservableCollection<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.Collections.ObjectModel;ObservableCollection<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;ReadOnlyCollection;(System.Collections.Generic.IList);;Argument[0].Element;Argument[this];taint;generated | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.ObjectModel;ReadOnlyCollection<>;false;get_Items;();;Argument[this];ReturnValue;taint;generated | @@ -1142,6 +1196,7 @@ summary | System.Collections.Specialized;NameObjectCollectionBase;true;get_Keys;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;NameValueCollection;false;Add;(System.Collections.Specialized.NameValueCollection);;Argument[0];Argument[this].Element;value;manual | | System.Collections.Specialized;NameValueCollection;false;Add;(System.String,System.String);;Argument[0];Argument[this];taint;generated | +| System.Collections.Specialized;NameValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;NameValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections.Specialized;NameValueCollection;false;Get;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;NameValueCollection;false;Get;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -1176,6 +1231,7 @@ summary | System.Collections.Specialized;StringCollection;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections.Specialized;StringCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;StringCollection;false;set_Item;(System.Int32,System.String);;Argument[1];Argument[this].Element;value;manual | +| System.Collections.Specialized;StringDictionary;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections.Specialized;StringDictionary;false;CopyTo;(System.Array,System.Int32);;Argument[this];Argument[0].Element;taint;generated | | System.Collections.Specialized;StringDictionary;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | | System.Collections.Specialized;StringDictionary;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | @@ -1208,6 +1264,7 @@ summary | System.Collections;BitArray;false;Xor;(System.Collections.BitArray);;Argument[this];ReturnValue;value;generated | | System.Collections;BitArray;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[0];Argument[this];taint;generated | +| System.Collections;CollectionBase;false;Remove;(System.Object);;Argument[this];Argument[0];taint;generated | | System.Collections;CollectionBase;false;get_InnerList;();;Argument[this];ReturnValue;taint;generated | | System.Collections;CollectionBase;false;get_List;();;Argument[this];ReturnValue;taint;generated | | System.Collections;CollectionBase;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | @@ -1252,6 +1309,7 @@ summary | System.Collections;ICollection;true;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.Collections;IDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;IDictionary;true;get_Item;(System.Object);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual | | System.Collections;IDictionary;true;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual | | System.Collections;IDictionary;true;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual | @@ -1259,9 +1317,11 @@ summary | System.Collections;IDictionary;true;set_Item;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections;IEnumerable;true;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Collections;IList;true;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual | +| System.Collections;IList;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;IList;true;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | | System.Collections;IList;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual | | System.Collections;IList;true;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual | +| System.Collections;Queue;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;Queue;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;Queue;false;Dequeue;();;Argument[this];ReturnValue;taint;generated | | System.Collections;Queue;false;Enqueue;(System.Object);;Argument[0];Argument[this];taint;generated | @@ -1285,6 +1345,7 @@ summary | System.Collections;SortedList;false;SortedList;(System.Collections.IDictionary,System.Collections.IComparer);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | | System.Collections;SortedList;false;Synchronized;(System.Collections.SortedList);;Argument[0].Element;ReturnValue;taint;generated | | System.Collections;SortedList;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | +| System.Collections;Stack;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Collections;Stack;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System.Collections;Stack;false;Peek;();;Argument[this].Element;ReturnValue;value;manual | | System.Collections;Stack;false;Pop;();;Argument[this].Element;ReturnValue;value;manual | @@ -1384,7 +1445,9 @@ summary | System.ComponentModel;BaseNumberConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[1];ReturnValue;taint;generated | | System.ComponentModel;BaseNumberConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | | System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.ComponentModel;BindingList<>;false;InsertItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[1];Argument[this];taint;generated | +| System.ComponentModel;BindingList<>;false;SetItem;(System.Int32,T);;Argument[this];Argument[1];taint;generated | | System.ComponentModel;CategoryAttribute;false;CategoryAttribute;(System.String);;Argument[0];Argument[this];taint;generated | | System.ComponentModel;CategoryAttribute;false;get_Category;();;Argument[this];ReturnValue;taint;generated | | System.ComponentModel;CharConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | @@ -1426,6 +1489,7 @@ summary | System.ComponentModel;EditorAttribute;false;get_TypeId;();;Argument[this];ReturnValue;taint;generated | | System.ComponentModel;EnumConverter;false;ConvertTo;(System.ComponentModel.ITypeDescriptorContext,System.Globalization.CultureInfo,System.Object,System.Type);;Argument[2];ReturnValue;taint;generated | | System.ComponentModel;EventDescriptorCollection;false;Add;(System.ComponentModel.EventDescriptor);;Argument[0];Argument[this].Element;value;manual | +| System.ComponentModel;EventDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel;EventDescriptorCollection;false;EventDescriptorCollection;(System.ComponentModel.EventDescriptor[]);;Argument[0].Element;Argument[this];taint;generated | | System.ComponentModel;EventDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual | | System.ComponentModel;EventDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | @@ -1510,6 +1574,7 @@ summary | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.ComponentModel.PropertyDescriptor);;Argument[0];Argument[this].Element;value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual | +| System.ComponentModel;PropertyDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.ComponentModel;PropertyDescriptorCollection;false;Insert;(System.Int32,System.ComponentModel.PropertyDescriptor);;Argument[1];Argument[this].Element;value;manual | @@ -1669,6 +1734,10 @@ summary | System.Data.Common;DataTableMappingCollection;false;set_Item;(System.String,System.Data.Common.DataTableMapping);;Argument[1];Argument[this].Element;value;manual | | System.Data.Common;DbCommand;false;ExecuteReader;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;ExecuteReader;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;();;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbCommand;false;ExecuteReaderAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Connection;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Parameters;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;false;get_Transaction;();;Argument[this];ReturnValue;taint;generated | @@ -1676,6 +1745,7 @@ summary | System.Data.Common;DbCommand;false;set_Connection;(System.Data.IDbConnection);;Argument[0];Argument[this];taint;generated | | System.Data.Common;DbCommand;false;set_Transaction;(System.Data.Common.DbTransaction);;Argument[0];Argument[this];taint;generated | | System.Data.Common;DbCommand;false;set_Transaction;(System.Data.IDbTransaction);;Argument[0];Argument[this];taint;generated | +| System.Data.Common;DbCommand;true;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommand;true;PrepareAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbCommandBuilder;false;GetDeleteCommand;(System.Boolean);;Argument[this];ReturnValue;taint;generated | @@ -1704,6 +1774,7 @@ summary | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String);;Argument[2];Argument[0];taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[1];Argument[0];taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;AppendKeyValuePair;(System.Text.StringBuilder,System.String,System.String,System.Boolean);;Argument[2];Argument[0];taint;generated | +| System.Data.Common;DbConnectionStringBuilder;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetProperties;();;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetProperties;(System.Attribute[]);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbConnectionStringBuilder;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated | @@ -1733,9 +1804,12 @@ summary | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[0];ReturnValue;taint;generated | | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[1];ReturnValue;taint;generated | | System.Data.Common;DbDataAdapter;true;CreateRowUpdatingEvent;(System.Data.DataRow,System.Data.IDbCommand,System.Data.StatementType,System.Data.Common.DataTableMapping);;Argument[3];ReturnValue;taint;generated | +| System.Data.Common;DbDataReader;false;GetFieldValueAsync<>;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetFieldValue<>;(System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.Data.Common;DbDataReader;true;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetProviderSpecificValue;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetProviderSpecificValues;(System.Object[]);;Argument[this];Argument[0].Element;taint;generated | +| System.Data.Common;DbDataReader;true;GetSchemaTableAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataReader;true;GetTextReader;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data.Common;DbDataRecord;false;GetPropertyOwner;(System.ComponentModel.PropertyDescriptor);;Argument[this];ReturnValue;value;generated | | System.Data.Common;DbEnumerator;false;DbEnumerator;(System.Data.IDataReader);;Argument[0];Argument[this];taint;generated | @@ -1838,6 +1912,7 @@ summary | System.Data;ConstraintCollection;false;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[0];Argument[this];taint;generated | | System.Data;ConstraintCollection;false;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[0];ReturnValue;taint;generated | | System.Data;ConstraintCollection;false;AddRange;(System.Data.Constraint[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;ConstraintCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;ConstraintCollection;false;CopyTo;(System.Data.Constraint[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;ConstraintCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;ConstraintCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -1870,15 +1945,20 @@ summary | System.Data;DataColumn;false;set_Prefix;(System.String);;Argument[0];Argument[this];taint;generated | | System.Data;DataColumnChangeEventArgs;false;DataColumnChangeEventArgs;(System.Data.DataRow,System.Data.DataColumn,System.Object);;Argument[1];Argument[this];taint;generated | | System.Data;DataColumnChangeEventArgs;false;get_Column;();;Argument[this];ReturnValue;taint;generated | +| System.Data;DataColumnCollection;false;Add;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;Add;(System.Data.DataColumn);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataColumnCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | +| System.Data;DataColumnCollection;false;Add;(System.String,System.Type);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataColumnCollection;false;Add;(System.String,System.Type,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;AddRange;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataColumnCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataColumnCollection;false;CopyTo;(System.Data.DataColumn[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataColumnCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataColumnCollection;false;get_List;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetDateTime;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetFieldValue<>;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | +| System.Data;DataReaderExtensions;false;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetGuid;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetProviderSpecificValue;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | | System.Data;DataReaderExtensions;false;GetString;(System.Data.Common.DbDataReader,System.String);;Argument[0].Element;ReturnValue;taint;generated | @@ -1910,11 +1990,18 @@ summary | System.Data;DataRelationCollection;false;Add;(System.Data.DataRelation);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataRelationCollection;false;CopyTo;(System.Data.DataRelation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataRelationCollection;false;Remove;(System.Data.DataRelation);;Argument[0];Argument[this];taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn,System.Boolean);;Argument[this];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.Data;DataRelationCollection;true;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[],System.Boolean);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRelationCollection;true;AddRange;(System.Data.DataRelation[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataRelationCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataRow;false;DataRow;(System.Data.DataRowBuilder);;Argument[0];Argument[this];taint;generated | | System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation);;Argument[this];ReturnValue;taint;generated | | System.Data;DataRow;false;GetChildRows;(System.Data.DataRelation,System.Data.DataRowVersion);;Argument[this];ReturnValue;taint;generated | @@ -1939,6 +2026,7 @@ summary | System.Data;DataRow;false;set_RowError;(System.String);;Argument[0];Argument[this];taint;generated | | System.Data;DataRowCollection;false;Add;(System.Data.DataRow);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataRowCollection;false;Add;(System.Object[]);;Argument[0];Argument[this].Element;value;manual | +| System.Data;DataRowCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataRowCollection;false;CopyTo;(System.Data.DataRow[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataRowCollection;false;Find;(System.Object);;Argument[this].Element;ReturnValue;value;manual | | System.Data;DataRowCollection;false;Find;(System.Object[]);;Argument[this].Element;ReturnValue;value;manual | @@ -2017,11 +2105,14 @@ summary | System.Data;DataTable;false;set_PrimaryKey;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this];taint;generated | | System.Data;DataTable;false;set_Site;(System.ComponentModel.ISite);;Argument[0];Argument[this];taint;generated | | System.Data;DataTable;false;set_TableName;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Data;DataTableCollection;false;Add;();;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;Add;(System.Data.DataTable);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataTableCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | | System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[1];ReturnValue;taint;generated | +| System.Data;DataTableCollection;false;Add;(System.String,System.String);;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;AddRange;(System.Data.DataTable[]);;Argument[0].Element;Argument[this].Element;value;manual | +| System.Data;DataTableCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Data;DataTableCollection;false;CopyTo;(System.Data.DataTable[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual | | System.Data;DataTableCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Data;DataTableCollection;false;get_Item;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -2598,7 +2689,10 @@ summary | System.IO.Compression;ZipArchiveEntry;false;get_LastWriteTime;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZipArchiveEntry;false;get_Name;();;Argument[this];ReturnValue;taint;generated | | System.IO.Compression;ZipArchiveEntry;false;set_LastWriteTime;(System.DateTimeOffset);;Argument[0];Argument[this];taint;generated | +| System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode);;Argument[0];ReturnValue;taint;generated | +| System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFile;false;Open;(System.String,System.IO.Compression.ZipArchiveMode,System.Text.Encoding);;Argument[2];ReturnValue;taint;generated | +| System.IO.Compression;ZipFile;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[0];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String);;Argument[2];ReturnValue;taint;generated | | System.IO.Compression;ZipFileExtensions;false;CreateEntryFromFile;(System.IO.Compression.ZipArchive,System.String,System.String,System.IO.Compression.CompressionLevel);;Argument[0];ReturnValue;taint;generated | @@ -2613,11 +2707,14 @@ summary | System.IO.IsolatedStorage;IsolatedStorage;false;get_DomainIdentity;();;Argument[this];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.IO.IsolatedStorage;IsolatedStorageFileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.IO.IsolatedStorage;IsolatedStorageFileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.IO.FileStream,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess,System.IO.HandleInheritability,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64);;Argument[0];ReturnValue;taint;generated | +| System.IO.MemoryMappedFiles;MemoryMappedFile;false;CreateFromFile;(System.String,System.IO.FileMode,System.String,System.Int64,System.IO.MemoryMappedFiles.MemoryMappedFileAccess);;Argument[0];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedFile;false;get_SafeMemoryMappedFileHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedViewAccessor;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO.MemoryMappedFiles;MemoryMappedViewStream;false;get_SafeMemoryMappedViewHandle;();;Argument[this];ReturnValue;taint;generated | @@ -2655,6 +2752,7 @@ summary | System.IO;BinaryReader;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.IO;BinaryWriter;false;BinaryWriter;(System.IO.Stream,System.Text.Encoding,System.Boolean);;Argument[1];Argument[this];taint;generated | +| System.IO;BinaryWriter;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;BinaryWriter;false;Write;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;BinaryWriter;false;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;BinaryWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | @@ -2694,8 +2792,19 @@ summary | System.IO;File;false;AppendAllLinesAsync;(System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Text.Encoding,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | | System.IO;File;false;AppendAllTextAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String,System.Int32);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Create;(System.String,System.Int32,System.IO.FileOptions);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;CreateSymbolicLink;(System.String,System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;Open;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;OpenHandle;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.IO.FileOptions,System.Int64);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenText;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;OpenWrite;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;ReadAllText;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;File;false;ReadAllText;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[0];ReturnValue;taint;generated | | System.IO;File;false;ReadLines;(System.String,System.Text.Encoding);;Argument[1];ReturnValue;taint;generated | @@ -2706,8 +2815,15 @@ summary | System.IO;File;false;WriteAllTextAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.IO;FileInfo;false;CopyTo;(System.String);;Argument[0];ReturnValue;taint;generated | | System.IO;FileInfo;false;CopyTo;(System.String,System.Boolean);;Argument[0];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Create;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;MoveTo;(System.String);;Argument[0];Argument[this];taint;generated | | System.IO;FileInfo;false;MoveTo;(System.String,System.Boolean);;Argument[0];Argument[this];taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;Open;(System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare);;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenRead;();;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenText;();;Argument[this];ReturnValue;taint;generated | +| System.IO;FileInfo;false;OpenWrite;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;get_Directory;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileInfo;false;get_DirectoryName;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileLoadException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | @@ -2723,10 +2839,8 @@ summary | System.IO;FileStream;false;FileStream;(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32,System.IO.FileOptions);;Argument[0];Argument[this];taint;manual | | System.IO;FileStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;FileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.IO;FileStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;FileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;FileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.IO;FileStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;FileStream;false;get_SafeFileHandle;();;Argument[this];ReturnValue;taint;generated | | System.IO;FileSystemEventArgs;false;FileSystemEventArgs;(System.IO.WatcherChangeTypes,System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.IO;FileSystemEventArgs;false;FileSystemEventArgs;(System.IO.WatcherChangeTypes,System.String,System.String);;Argument[2];Argument[this];taint;generated | @@ -2811,6 +2925,7 @@ summary | System.IO;Stream;false;CopyToAsync;(System.IO.Stream);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;false;CopyToAsync;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;false;CopyToAsync;(System.IO.Stream,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | +| System.IO;Stream;false;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;false;ReadAsync;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;Stream;false;Synchronized;(System.IO.Stream);;Argument[0];ReturnValue;taint;generated | | System.IO;Stream;false;WriteAsync;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | @@ -2818,10 +2933,13 @@ summary | System.IO;Stream;true;BeginWrite;(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object);;Argument[0].Element;Argument[this];taint;manual | | System.IO;Stream;true;CopyTo;(System.IO.Stream,System.Int32);;Argument[this];Argument[0];taint;manual | | System.IO;Stream;true;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;manual | +| System.IO;Stream;true;FlushAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;true;Read;(System.Byte[],System.Int32,System.Int32);;Argument[this];Argument[0].Element;taint;manual | | System.IO;Stream;true;ReadAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[this];Argument[0].Element;taint;manual | +| System.IO;Stream;true;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;Stream;true;Write;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;manual | | System.IO;Stream;true;WriteAsync;(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken);;Argument[0].Element;Argument[this];taint;manual | +| System.IO;Stream;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;StreamReader;false;StreamReader;(System.IO.Stream);;Argument[0];Argument[this];taint;manual | | System.IO;StreamReader;false;StreamReader;(System.IO.Stream,System.Boolean);;Argument[0];Argument[this];taint;manual | | System.IO;StreamReader;false;StreamReader;(System.IO.Stream,System.Text.Encoding);;Argument[0];Argument[this];taint;manual | @@ -2847,10 +2965,13 @@ summary | System.IO;StringWriter;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.IO;StringWriter;false;Write;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;StringWriter;false;Write;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;Write;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;StringWriter;false;WriteAsync;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | | System.IO;StringWriter;false;WriteLineAsync;(System.String);;Argument[0];Argument[this];taint;generated | +| System.IO;StringWriter;false;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[0];Argument[this];taint;generated | | System.IO;TextReader;false;Synchronized;(System.IO.TextReader);;Argument[0];ReturnValue;taint;generated | | System.IO;TextReader;true;Read;();;Argument[this];ReturnValue;taint;manual | | System.IO;TextReader;true;Read;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;manual | @@ -2868,7 +2989,12 @@ summary | System.IO;TextWriter;false;Synchronized;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;false;TextWriter;(System.IFormatProvider);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;false;WriteAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | +| System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;false;WriteLineAsync;(System.Char[]);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;FlushAsync;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;Write;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.Object);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object);;Argument[0];Argument[this];taint;generated | @@ -2882,7 +3008,14 @@ summary | System.IO;TextWriter;true;Write;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;Write;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLine;(System.Char[]);;Argument[0].Element;Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | @@ -2899,8 +3032,18 @@ summary | System.IO;TextWriter;true;WriteLine;(System.String,System.Object,System.Object,System.Object);;Argument[3];Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[0];Argument[this];taint;generated | | System.IO;TextWriter;true;WriteLine;(System.String,System.Object[]);;Argument[1].Element;Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteLine;(System.Text.StringBuilder);;Argument[0];Argument[this];taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;();;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[0].Element;ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Char[],System.Int32,System.Int32);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.String);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | +| System.IO;TextWriter;true;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;get_FormatProvider;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;get_NewLine;();;Argument[this];ReturnValue;taint;generated | | System.IO;TextWriter;true;set_NewLine;(System.String);;Argument[0];Argument[this];taint;generated | @@ -4093,8 +4236,10 @@ summary | System.Net.Http.Headers;HeaderStringValues+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HeaderStringValues;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HeaderStringValues;false;ToString;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Http.Headers;HttpHeaders;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net.Http.Headers;HttpHeaders;false;get_NonValidated;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Http.Headers;HttpHeadersNonValidated;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValue;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;TryGetValues;(System.String,System.Net.Http.Headers.HeaderStringValues);;Argument[0];ReturnValue;taint;generated | | System.Net.Http.Headers;HttpHeadersNonValidated;false;get_Item;(System.String);;Argument[0];ReturnValue;taint;generated | @@ -4194,12 +4339,17 @@ summary | System.Net.Http.Json;JsonContent;false;Create<>;(T,System.Net.Http.Headers.MediaTypeHeaderValue,System.Text.Json.JsonSerializerOptions);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Http;ByteArrayContent;false;ByteArrayContent;(System.Byte[],System.Int32,System.Int32);;Argument[0].Element;Argument[this];taint;generated | +| System.Net.Http;ByteArrayContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;ByteArrayContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;DelegatingHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated | | System.Net.Http;DelegatingHandler;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;get_InnerHandler;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;DelegatingHandler;false;set_InnerHandler;(System.Net.Http.HttpMessageHandler);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;FormUrlEncodedContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage);;Argument[this];Argument[0];taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption);;Argument[this];Argument[0];taint;generated | | System.Net.Http;HttpClient;false;Send;(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | @@ -4226,7 +4376,10 @@ summary | System.Net.Http;HttpContent;false;ReadAsStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpContent;false;get_Headers;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpContent;true;CreateContentReadStream;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;HttpContent;true;CreateContentReadStreamAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;HttpContent;true;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Http;HttpMessageInvoker;false;HttpMessageInvoker;(System.Net.Http.HttpMessageHandler,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Http;HttpMessageInvoker;false;SendAsync;(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Http;HttpMethod;false;HttpMethod;(System.String);;Argument[0];Argument[this];taint;generated | @@ -4262,6 +4415,7 @@ summary | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent);;Argument[0];Argument[this].Element;value;manual | | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent,System.String);;Argument[0];Argument[this];taint;generated | | System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent,System.String,System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;ReadOnlyMemoryContent;false;CreateContentReadStreamAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;ReadOnlyMemoryContent;false;ReadOnlyMemoryContent;(System.ReadOnlyMemory);;Argument[0];Argument[this];taint;generated | | System.Net.Http;SocketsHttpConnectionContext;false;get_DnsEndPoint;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;SocketsHttpConnectionContext;false;get_InitialRequestMessage;();;Argument[this];ReturnValue;taint;generated | @@ -4300,9 +4454,13 @@ summary | System.Net.Http;SocketsHttpPlaintextStreamFilterContext;false;get_NegotiatedHttpVersion;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;SocketsHttpPlaintextStreamFilterContext;false;get_PlaintextStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];Argument[0];taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | +| System.Net.Http;StreamContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | | System.Net.Http;StreamContent;false;StreamContent;(System.IO.Stream,System.Int32);;Argument[0];Argument[this];taint;generated | +| System.Net.Http;StringContent;false;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[0];ReturnValue;taint;generated | | System.Net.Mail;AlternateView;false;CreateAlternateViewFromString;(System.String,System.Net.Mime.ContentType);;Argument[1];ReturnValue;taint;generated | @@ -4332,7 +4490,10 @@ summary | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.IO.Stream,System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.Net.Mime.ContentType);;Argument[1];Argument[this];taint;generated | +| System.Net.Mail;AttachmentBase;false;AttachmentBase;(System.String,System.String);;Argument[0];Argument[this];taint;generated | | System.Net.Mail;AttachmentBase;false;get_ContentId;();;Argument[this];ReturnValue;taint;generated | | System.Net.Mail;AttachmentBase;false;get_ContentStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Mail;AttachmentBase;false;set_ContentType;(System.Net.Mime.ContentType);;Argument[0];Argument[this];taint;generated | @@ -4428,6 +4589,7 @@ summary | System.Net.NetworkInformation;PhysicalAddress;false;PhysicalAddress;(System.Byte[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.NetworkInformation;UnicastIPAddressInformationCollection;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;AuthenticatedStream;false;AuthenticatedStream;(System.IO.Stream,System.Boolean);;Argument[0];Argument[this];taint;generated | +| System.Net.Security;AuthenticatedStream;false;DisposeAsync;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;AuthenticatedStream;false;get_InnerStream;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[1];Argument[this];taint;generated | | System.Net.Security;NegotiateStream;false;AuthenticateAsClient;(System.Net.NetworkCredential,System.Security.Authentication.ExtendedProtection.ChannelBinding,System.String);;Argument[2];Argument[this];taint;generated | @@ -4448,10 +4610,8 @@ summary | System.Net.Security;NegotiateStream;false;FlushAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.Net.Security;NegotiateStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.Net.Security;NegotiateStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Security;NegotiateStream;false;get_RemoteIdentity;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslApplicationProtocol;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.Net.Security;SslApplicationProtocol;false;get_Protocol;();;Argument[this];ReturnValue;taint;generated | @@ -4482,12 +4642,11 @@ summary | System.Net.Sockets;NetworkStream;false;NetworkStream;(System.Net.Sockets.Socket,System.IO.FileAccess,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;NetworkStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;NetworkStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.Net.Sockets;NetworkStream;false;ReadAsync;(System.Memory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;NetworkStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | -| System.Net.Sockets;NetworkStream;false;WriteAsync;(System.ReadOnlyMemory,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;NetworkStream;false;get_Socket;();;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;SafeSocketHandle;false;SafeSocketHandle;(System.IntPtr,System.Boolean);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;Accept;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;AcceptAsync;(System.Net.Sockets.Socket,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | @@ -4511,6 +4670,7 @@ summary | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Boolean,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;DisconnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);;Argument[this];Argument[0];taint;generated | +| System.Net.Sockets;Socket;false;EndAccept;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | @@ -4527,6 +4687,7 @@ summary | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.EndPoint);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;ReceiveFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | @@ -4536,6 +4697,7 @@ summary | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[4];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];Argument[this];taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFrom;(System.Span,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Net.Sockets.IPPacketInformation);;Argument[2];ReturnValue;taint;generated | +| System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[2];ReturnValue;taint;generated | | System.Net.Sockets;Socket;false;ReceiveMessageFromAsync;(System.Memory,System.Net.Sockets.SocketFlags,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | @@ -4583,6 +4745,7 @@ summary | System.Net.Sockets;SocketAsyncEventArgs;false;set_SendPacketsElements;(System.Net.Sockets.SendPacketsElement[]);;Argument[0].Element;Argument[this];taint;generated | | System.Net.Sockets;SocketAsyncEventArgs;false;set_UserToken;(System.Object);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;SocketException;false;get_Message;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint);;Argument[1];Argument[0];taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ConnectAsync;(System.Net.Sockets.Socket,System.Net.EndPoint,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated | @@ -4594,6 +4757,8 @@ summary | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[1];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;ReceiveAsync;(System.Net.Sockets.Socket,System.Memory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated | +| System.Net.Sockets;SocketTaskExtensions;false;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendAsync;(System.Net.Sockets.Socket,System.ReadOnlyMemory,System.Net.Sockets.SocketFlags,System.Threading.CancellationToken);;Argument[3];ReturnValue;taint;generated | | System.Net.Sockets;SocketTaskExtensions;false;SendToAsync;(System.Net.Sockets.Socket,System.ArraySegment,System.Net.Sockets.SocketFlags,System.Net.EndPoint);;Argument[3];Argument[0];taint;generated | @@ -4608,6 +4773,8 @@ summary | System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;AcceptSocketAsync;(System.Threading.CancellationToken);;Argument[this];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;AcceptTcpClient;();;Argument[this];ReturnValue;taint;generated | +| System.Net.Sockets;TcpListener;false;EndAcceptSocket;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net.Sockets;TcpListener;false;EndAcceptTcpClient;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPAddress,System.Int32);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;TcpListener;false;TcpListener;(System.Net.IPEndPoint);;Argument[0];Argument[this];taint;generated | | System.Net.Sockets;TcpListener;false;get_LocalEndpoint;();;Argument[this];ReturnValue;taint;generated | @@ -4693,11 +4860,17 @@ summary | System.Net;CookieCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;value;generated | | System.Net;CookieException;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | | System.Net;CredentialCache;false;GetCredential;(System.Uri,System.String);;Argument[this];ReturnValue;taint;generated | +| System.Net;Dns;false;EndGetHostAddresses;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndGetHostByName;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndGetHostEntry;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;Dns;false;EndResolve;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;DnsEndPoint;false;DnsEndPoint;(System.String,System.Int32,System.Net.Sockets.AddressFamily);;Argument[0];Argument[this];taint;generated | | System.Net;DnsEndPoint;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.Net;DnsEndPoint;false;get_Host;();;Argument[this];ReturnValue;taint;generated | | System.Net;DownloadDataCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated | | System.Net;DownloadStringCompletedEventArgs;false;get_Result;();;Argument[this];ReturnValue;taint;generated | +| System.Net;FileWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;FileWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated | | System.Net;FileWebRequest;false;get_ContentType;();;Argument[this];ReturnValue;taint;generated | @@ -4772,6 +4945,9 @@ summary | System.Net;HttpListenerTimeoutManager;false;get_IdleConnection;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpListenerTimeoutManager;false;set_DrainEntityBody;(System.TimeSpan);;Argument[0];Argument[this];taint;generated | | System.Net;HttpListenerTimeoutManager;false;set_IdleConnection;(System.TimeSpan);;Argument[0];Argument[this];taint;generated | +| System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;HttpWebRequest;false;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);;Argument[0];ReturnValue;taint;generated | +| System.Net;HttpWebRequest;false;EndGetResponse;(System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetRequestStream;();;Argument[this];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetRequestStream;(System.Net.TransportContext);;Argument[this];ReturnValue;taint;generated | | System.Net;HttpWebRequest;false;GetResponse;();;Argument[this];ReturnValue;taint;generated | @@ -4857,6 +5033,8 @@ summary | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest);;Argument[0];ReturnValue;taint;generated | | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];Argument[this];taint;generated | | System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[0];ReturnValue;taint;generated | +| System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];Argument[this];taint;generated | +| System.Net;WebClient;false;GetWebResponse;(System.Net.WebRequest,System.IAsyncResult);;Argument[1];ReturnValue;taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];Argument[this];taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Net;WebClient;false;OpenRead;(System.String);;Argument[this];ReturnValue;taint;generated | @@ -4977,6 +5155,7 @@ summary | System.Net;WebException;false;WebException;(System.String,System.Exception,System.Net.WebExceptionStatus,System.Net.WebResponse);;Argument[3];Argument[this];taint;generated | | System.Net;WebException;false;get_Response;();;Argument[this];ReturnValue;taint;generated | | System.Net;WebHeaderCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual | +| System.Net;WebHeaderCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Net;WebHeaderCollection;false;ToByteArray;();;Argument[this];ReturnValue;taint;generated | | System.Net;WebHeaderCollection;false;ToString;();;Argument[this];ReturnValue;taint;generated | | System.Net;WebHeaderCollection;false;get_AllKeys;();;Argument[this];ReturnValue;taint;generated | @@ -5002,7 +5181,6 @@ summary | System.Numerics;BigInteger;false;Max;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Min;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[1];ReturnValue;taint;generated | -| System.Numerics;BigInteger;false;Negate;(System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Pow;(System.Numerics.BigInteger,System.Int32);;Argument[0];ReturnValue;taint;generated | | System.Numerics;BigInteger;false;Remainder;(System.Numerics.BigInteger,System.Numerics.BigInteger);;Argument[0];ReturnValue;taint;generated | | System.Numerics;Complex;false;ToString;(System.IFormatProvider);;Argument[0];ReturnValue;taint;generated | @@ -5727,9 +5905,11 @@ summary | System.Resources;ResourceReader;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Resources;ResourceReader;false;GetResourceData;(System.String,System.String,System.Byte[]);;Argument[this];ReturnValue;taint;generated | | System.Resources;ResourceReader;false;ResourceReader;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | +| System.Resources;ResourceSet;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Resources;ResourceSet;false;ResourceSet;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | | System.Resources;ResourceSet;false;ResourceSet;(System.Resources.IResourceReader);;Argument[0].Element;Argument[this];taint;generated | | System.Resources;ResourceWriter;false;ResourceWriter;(System.IO.Stream);;Argument[0];Argument[this];taint;generated | +| System.Resources;ResourceWriter;false;ResourceWriter;(System.String);;Argument[0];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncIteratorMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncIteratorMethodBuilder;false;AwaitUnsafeOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncTaskMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | @@ -5746,6 +5926,7 @@ summary | System.Runtime.CompilerServices;AsyncValueTaskMethodBuilder<>;false;SetResult;(TResult);;Argument[0];Argument[this];taint;generated | | System.Runtime.CompilerServices;AsyncValueTaskMethodBuilder<>;false;get_Task;();;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;CallSite;false;get_Binder;();;Argument[this];ReturnValue;taint;generated | +| System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetOrCreateValue;(TKey);;Argument[0];ReturnValue;taint;generated | | System.Runtime.CompilerServices;ConfiguredCancelableAsyncEnumerable<>;false;ConfigureAwait;(System.Boolean);;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;ConfiguredCancelableAsyncEnumerable<>;false;GetAsyncEnumerator;();;Argument[this];ReturnValue;taint;generated | @@ -5763,8 +5944,6 @@ summary | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider);;Argument[2];Argument[this];taint;generated | | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[2];Argument[this];taint;generated | | System.Runtime.CompilerServices;DefaultInterpolatedStringHandler;false;DefaultInterpolatedStringHandler;(System.Int32,System.Int32,System.IFormatProvider,System.Span);;Argument[3];Argument[this];taint;generated | -| System.Runtime.CompilerServices;DynamicAttribute;false;DynamicAttribute;(System.Boolean[]);;Argument[0].Element;Argument[this];taint;generated | -| System.Runtime.CompilerServices;DynamicAttribute;false;get_TransformFlags;();;Argument[this];ReturnValue;taint;generated | | System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[0];ReturnValue;taint;generated | | System.Runtime.CompilerServices;FormattableStringFactory;false;Create;(System.String,System.Object[]);;Argument[1].Element;ReturnValue;taint;generated | | System.Runtime.CompilerServices;PoolingAsyncValueTaskMethodBuilder;false;AwaitOnCompleted<,>;(TAwaiter,TStateMachine);;Argument[1];Argument[this];taint;generated | @@ -6109,6 +6288,7 @@ summary | System.Security.Cryptography.X509Certificates;X509Certificate;false;ToString;(System.Boolean);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Issuer;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509Certificate;false;get_Subject;();;Argument[this];ReturnValue;taint;generated | +| System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;false;get_Current;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;Add;(System.Security.Cryptography.X509Certificates.X509Certificate);;Argument[0];Argument[this].Element;value;manual | | System.Security.Cryptography.X509Certificates;X509CertificateCollection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);;Argument[0].Element;Argument[this].Element;value;manual | @@ -6240,6 +6420,7 @@ summary | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;get_SyncRoot;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;EncryptionPropertyCollection;false;set_ItemOf;(System.Int32,System.Security.Cryptography.Xml.EncryptionProperty);;Argument[1];Argument[this];taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;AddClause;(System.Security.Cryptography.Xml.KeyInfoClause);;Argument[0];Argument[this];taint;generated | +| System.Security.Cryptography.Xml;KeyInfo;false;GetEnumerator;(System.Type);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;LoadXml;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;get_Id;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;KeyInfo;false;set_Id;(System.String);;Argument[0];Argument[this];taint;generated | @@ -6351,6 +6532,7 @@ summary | System.Security.Cryptography.Xml;Transform;false;set_Context;(System.Xml.XmlElement);;Argument[0].Element;Argument[this];taint;generated | | System.Security.Cryptography.Xml;Transform;false;set_Resolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;TransformChain;false;Add;(System.Security.Cryptography.Xml.Transform);;Argument[0];Argument[this];taint;generated | +| System.Security.Cryptography.Xml;TransformChain;false;GetEnumerator;();;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;TransformChain;false;get_Item;(System.Int32);;Argument[this];ReturnValue;taint;generated | | System.Security.Cryptography.Xml;XmlDecryptionTransform;false;AddExceptUri;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography.Xml;XmlDecryptionTransform;false;GetOutput;();;Argument[this];ReturnValue;taint;generated | @@ -6483,6 +6665,7 @@ summary | System.Security.Cryptography;RSAPKCS1SignatureFormatter;false;SetHashAlgorithm;(System.String);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;RSAPKCS1SignatureFormatter;false;SetKey;(System.Security.Cryptography.AsymmetricAlgorithm);;Argument[0];Argument[this];taint;generated | | System.Security.Cryptography;SafeEvpPKeyHandle;false;DuplicateHandle;();;Argument[this];ReturnValue;taint;generated | +| System.Security.Policy;Evidence;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Security.Principal;GenericIdentity;false;Clone;();;Argument[this];ReturnValue;taint;generated | | System.Security.Principal;GenericIdentity;false;GenericIdentity;(System.Security.Principal.GenericIdentity);;Argument[0];Argument[this];taint;generated | | System.Security.Principal;GenericIdentity;false;GenericIdentity;(System.String);;Argument[0];Argument[this];taint;generated | @@ -6518,6 +6701,7 @@ summary | System.Text.Encodings.Web;TextEncoder;true;Encode;(System.IO.TextWriter,System.String,System.Int32,System.Int32);;Argument[1];Argument[0];taint;generated | | System.Text.Encodings.Web;TextEncoder;true;Encode;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[0];Argument[this];taint;generated | +| System.Text.Json.Nodes;JsonArray;false;Add<>;(T);;Argument[this];Argument[0];taint;generated | | System.Text.Json.Nodes;JsonArray;false;Create;(System.Text.Json.JsonElement,System.Nullable);;Argument[0];ReturnValue;taint;generated | | System.Text.Json.Nodes;JsonArray;false;JsonArray;(System.Text.Json.Nodes.JsonNodeOptions,System.Text.Json.Nodes.JsonNode[]);;Argument[this];Argument[1].Element;taint;generated | | System.Text.Json.Nodes;JsonArray;false;JsonArray;(System.Text.Json.Nodes.JsonNode[]);;Argument[this];Argument[0].Element;taint;generated | @@ -6814,6 +6998,7 @@ summary | System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[0];Argument[this].Element;value;manual | | System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[this];ReturnValue;value;manual | | System.Text;StringBuilder;false;AppendLine;(System.Text.StringBuilder+AppendInterpolatedStringHandler);;Argument[this];ReturnValue;taint;generated | +| System.Text;StringBuilder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual | | System.Text;StringBuilder;false;GetChunks;();;Argument[this];ReturnValue;taint;generated | | System.Text;StringBuilder;false;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);;Argument[this];Argument[0];taint;generated | | System.Text;StringBuilder;false;Insert;(System.Int32,System.Boolean);;Argument[this];ReturnValue;taint;generated | @@ -6885,6 +7070,10 @@ summary | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;Receive<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan);;Argument[0];ReturnValue;taint;generated | +| System.Threading.Tasks.Dataflow;DataflowBlock;false;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock,System.TimeSpan,System.Threading.CancellationToken);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock,TInput,System.Threading.CancellationToken);;Argument[1];Argument[0];taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlock;false;TryReceive<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock,TOutput);;Argument[0];ReturnValue;taint;generated | | System.Threading.Tasks.Dataflow;DataflowBlockOptions;false;get_CancellationToken;();;Argument[this];ReturnValue;taint;generated | @@ -7448,6 +7637,7 @@ summary | System.Xml.Linq;XText;false;XText;(System.Xml.Linq.XText);;Argument[0];Argument[this];taint;generated | | System.Xml.Linq;XText;false;get_Value;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Linq;XText;false;set_Value;(System.String);;Argument[0];Argument[this];taint;generated | +| System.Xml.Resolvers;XmlPreloadedResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;XmlPreloadedResolver;(System.Xml.XmlResolver,System.Xml.Resolvers.XmlKnownDtds,System.Collections.Generic.IEqualityComparer);;Argument[0];Argument[this];taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;XmlPreloadedResolver;(System.Xml.XmlResolver,System.Xml.Resolvers.XmlKnownDtds,System.Collections.Generic.IEqualityComparer);;Argument[2];Argument[this];taint;generated | | System.Xml.Resolvers;XmlPreloadedResolver;false;set_Credentials;(System.Net.ICredentials);;Argument[0];Argument[this];taint;generated | @@ -7676,9 +7866,12 @@ summary | System.Xml.Schema;XmlSchemaSet;false;Add;(System.String,System.Xml.XmlReader);;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;Add;(System.Xml.Schema.XmlSchemaSet);;Argument[0];Argument[this];taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);;Argument[this];Argument[0].Element;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Remove;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;Reprocess;(System.Xml.Schema.XmlSchema);;Argument[0];ReturnValue;taint;generated | +| System.Xml.Schema;XmlSchemaSet;false;Schemas;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;XmlSchemaSet;(System.Xml.XmlNameTable);;Argument[0];Argument[this];taint;generated | | System.Xml.Schema;XmlSchemaSet;false;get_CompilationSettings;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaSet;false;get_GlobalAttributes;();;Argument[this];ReturnValue;taint;generated | @@ -7765,8 +7958,10 @@ summary | System.Xml.Schema;XmlSchemaXPath;false;get_XPath;();;Argument[this];ReturnValue;taint;generated | | System.Xml.Schema;XmlSchemaXPath;false;set_XPath;(System.String);;Argument[0];Argument[this];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;CodeIdentifiers;false;Add;(System.String,System.Object);;Argument[this];Argument[1];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[0];ReturnValue;taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;CodeIdentifiers;false;AddUnique;(System.String,System.Object);;Argument[this];Argument[1];taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;MakeUnique;(System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml.Serialization;CodeIdentifiers;false;ToArray;(System.Type);;Argument[this];ReturnValue;taint;generated | | System.Xml.Serialization;ImportContext;false;ImportContext;(System.Xml.Serialization.CodeIdentifiers,System.Boolean);;Argument[0];Argument[this];taint;generated | @@ -8072,6 +8267,7 @@ summary | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteElementStringRaw;(System.String,System.String,System.Xml.XmlQualifiedName);;Argument[1];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteId;(System.Object);;Argument[this];Argument[0];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncoded;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.Byte[],System.Xml.XmlQualifiedName);;Argument[2].Element;Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringEncodedRaw;(System.String,System.String,System.String,System.Xml.XmlQualifiedName);;Argument[2];Argument[this];taint;generated | @@ -8079,9 +8275,15 @@ summary | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.Byte[]);;Argument[2].Element;Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteNullableStringLiteralRaw;(System.String,System.String,System.String);;Argument[2];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[2];Argument[this];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WritePotentiallyReferencingElement;(System.String,System.String,System.Object,System.Type,System.Boolean,System.Boolean);;Argument[this];Argument[2];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object);;Argument[this];Argument[2];taint;generated | +| System.Xml.Serialization;XmlSerializationWriter;false;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);;Argument[this];Argument[2];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[0];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteRpcResult;(System.String,System.String);;Argument[1];Argument[this];taint;generated | | System.Xml.Serialization;XmlSerializationWriter;false;WriteSerializable;(System.Xml.Serialization.IXmlSerializable,System.String,System.String,System.Boolean);;Argument[0];Argument[this];taint;generated | @@ -8657,6 +8859,7 @@ summary | System.Xml;XmlReaderSettings;false;set_XmlResolver;(System.Xml.XmlResolver);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlResolver;true;ResolveUri;(System.Uri,System.String);;Argument[1];ReturnValue;taint;generated | +| System.Xml;XmlSecureResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlSecureResolver;false;XmlSecureResolver;(System.Xml.XmlResolver,System.String);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlSecureResolver;false;set_Credentials;(System.Net.ICredentials);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlSignificantWhitespace;false;CloneNode;(System.Boolean);;Argument[this];ReturnValue;taint;generated | @@ -8684,6 +8887,7 @@ summary | System.Xml;XmlTextWriter;false;XmlTextWriter;(System.IO.TextWriter);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlTextWriter;false;get_BaseStream;();;Argument[this];ReturnValue;taint;generated | | System.Xml;XmlTextWriter;false;get_XmlLang;();;Argument[this];ReturnValue;taint;generated | +| System.Xml;XmlUrlResolver;false;GetEntity;(System.Uri,System.String,System.Type);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlUrlResolver;false;set_Credentials;(System.Net.ICredentials);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlUrlResolver;false;set_Proxy;(System.Net.IWebProxy);;Argument[0];Argument[this];taint;generated | | System.Xml;XmlValidatingReader;false;LookupNamespace;(System.String);;Argument[0];ReturnValue;taint;generated | @@ -8701,6 +8905,8 @@ summary | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.IO.TextWriter,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | +| System.Xml;XmlWriter;false;Create;(System.String);;Argument[0];ReturnValue;taint;generated | +| System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[0];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.String,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.Text.StringBuilder,System.Xml.XmlWriterSettings);;Argument[1];ReturnValue;taint;generated | | System.Xml;XmlWriter;false;Create;(System.Xml.XmlWriter);;Argument[0];ReturnValue;taint;generated | @@ -8754,6 +8960,8 @@ summary | System;ArgumentOutOfRangeException;false;get_ActualValue;();;Argument[this];ReturnValue;taint;generated | | System;ArgumentOutOfRangeException;false;get_Message;();;Argument[this];ReturnValue;taint;generated | | System;Array;false;AsReadOnly<>;(T[]);;Argument[0].Element;ReturnValue.Element;value;manual | +| System;Array;false;Clear;(System.Array);;Argument[0].WithoutElement;Argument[0];value;manual | +| System;Array;false;Clear;(System.Array,System.Int32,System.Int32);;Argument[0].WithoutElement;Argument[0];value;manual | | System;Array;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual | | System;Array;false;CopyTo;(System.Array,System.Int64);;Argument[this].Element;Argument[0].Element;value;manual | | System;Array;false;Fill<>;(T[],T);;Argument[1];Argument[0].Element;taint;generated | @@ -9773,6 +9981,27 @@ summary | System;TupleExtensions;false;Deconstruct<,>;(System.Tuple,T1,T2);;Argument[0].Property[System.Tuple<,>.Item1];Argument[1];value;manual | | System;TupleExtensions;false;Deconstruct<,>;(System.Tuple,T1,T2);;Argument[0].Property[System.Tuple<,>.Item2];Argument[2];value;manual | | System;TupleExtensions;false;Deconstruct<>;(System.Tuple,T1);;Argument[0].Property[System.Tuple<>.Item1];Argument[1];value;manual | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple>>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,,>;(System.ValueTuple>);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<,>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | +| System;TupleExtensions;false;ToTuple<>;(System.ValueTuple);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | | System;TupleExtensions;false;ToValueTuple<,,,,,,,,,,,,,,,,,,>;(System.Tuple>>);;Argument[0];ReturnValue;taint;generated | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql index 849500904a0..5ee4c6e27a9 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql @@ -7,7 +7,9 @@ class CallableWithSplitting extends Callable { CallableWithSplitting() { this = any(SplitControlFlowElement e).getEnclosingCallable() } } -query predicate defReadInconsistency(AssignableRead ar, Expr e, PreSsa::SourceVariable v, boolean b) { +query predicate defReadInconsistency( + AssignableRead ar, Expr e, PreSsa::SsaInput::SourceVariable v, boolean b +) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions not ar.getEnclosingCallable() instanceof CallableWithSplitting and @@ -36,7 +38,8 @@ query predicate defReadInconsistency(AssignableRead ar, Expr e, PreSsa::SourceVa } query predicate readReadInconsistency( - LocalScopeVariableRead read1, LocalScopeVariableRead read2, PreSsa::SourceVariable v, boolean b + LocalScopeVariableRead read1, LocalScopeVariableRead read2, PreSsa::SsaInput::SourceVariable v, + boolean b ) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions @@ -50,7 +53,7 @@ query predicate readReadInconsistency( b = false and v = read1.getTarget() and SsaImpl::adjacentReadPairSameVar(_, read1.getAControlFlowNode(), read2.getAControlFlowNode()) and - read1.getTarget() instanceof PreSsa::SourceVariable and + read1.getTarget() instanceof PreSsa::SsaInput::SourceVariable and not PreSsa::adjacentReadPairSameVar(read1, read2) and // Exclude split CFG elements because SSA may be more precise than pre-SSA // in those cases @@ -59,7 +62,9 @@ query predicate readReadInconsistency( ) } -query predicate phiInconsistency(ControlFlowElement cfe, Expr e, PreSsa::SourceVariable v, boolean b) { +query predicate phiInconsistency( + ControlFlowElement cfe, Expr e, PreSsa::SsaInput::SourceVariable v, boolean b +) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions not cfe.getEnclosingCallable() instanceof CallableWithSplitting and diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql index abc40f41e8d..f9603dc1da2 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.dataflow.internal.SsaImplCommon +import semmle.code.csharp.dataflow.internal.SsaImpl from Ssa::SourceVariable v, ControlFlow::BasicBlock bb where phiReadExposedForTesting(bb, v) diff --git a/csharp/ql/test/query-tests/Bad Practices/Comments/TodoComments/TodoComments.expected b/csharp/ql/test/query-tests/Bad Practices/Comments/TodoComments/TodoComments.expected index 523bbf79f23..8afce1f3506 100644 --- a/csharp/ql/test/query-tests/Bad Practices/Comments/TodoComments/TodoComments.expected +++ b/csharp/ql/test/query-tests/Bad Practices/Comments/TodoComments/TodoComments.expected @@ -1,3 +1,3 @@ -| TodoComments.cs:4:5:4:26 | // ... | TODO comment. | -| TodoComments.cs:5:5:5:27 | // ... | TODO comment. | -| TodoCommentsBad.cs:7:9:7:41 | // ... | TODO comment. | +| TodoComments.cs:4:5:4:26 | // ... | TODO comments should be addressed. | +| TodoComments.cs:5:5:5:27 | // ... | TODO comments should be addressed. | +| TodoCommentsBad.cs:7:9:7:41 | // ... | TODO comments should be addressed. | diff --git a/csharp/ql/test/query-tests/EmptyBlock/EmptyBlock.expected b/csharp/ql/test/query-tests/EmptyBlock/EmptyBlock.expected index fc4b22de031..693e6df4898 100644 --- a/csharp/ql/test/query-tests/EmptyBlock/EmptyBlock.expected +++ b/csharp/ql/test/query-tests/EmptyBlock/EmptyBlock.expected @@ -1,3 +1,3 @@ -| EmptyBlock.cs:9:9:10:9 | {...} | Empty block. | -| EmptyBlock.cs:26:9:27:9 | {...} | Empty block. | -| EmptyBlock.cs:48:9:49:9 | {...} | Empty block. | +| EmptyBlock.cs:9:9:10:9 | {...} | Empty block without comment. | +| EmptyBlock.cs:26:9:27:9 | {...} | Empty block without comment. | +| EmptyBlock.cs:48:9:49:9 | {...} | Empty block without comment. | diff --git a/csharp/ql/test/query-tests/Likely Bugs/Collections/ContainerLengthCmpOffByOne/ContainerLengthCmpOffByOne.expected b/csharp/ql/test/query-tests/Likely Bugs/Collections/ContainerLengthCmpOffByOne/ContainerLengthCmpOffByOne.expected index 133ea2ad6a2..616384fb1e4 100644 --- a/csharp/ql/test/query-tests/Likely Bugs/Collections/ContainerLengthCmpOffByOne/ContainerLengthCmpOffByOne.expected +++ b/csharp/ql/test/query-tests/Likely Bugs/Collections/ContainerLengthCmpOffByOne/ContainerLengthCmpOffByOne.expected @@ -1,4 +1,4 @@ -| ContainerLengthCmpOffByOne.cs:8:25:8:40 | ... <= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:10:31:10:37 | access to array element | access to array element | -| ContainerLengthCmpOffByOne.cs:14:25:14:40 | ... >= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:16:31:16:37 | access to array element | access to array element | -| ContainerLengthCmpOffByOne.cs:27:13:27:28 | ... <= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:29:31:29:37 | access to array element | access to array element | -| ContainerLengthCmpOffByOne.cs:33:13:33:28 | ... >= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:35:31:35:37 | access to array element | access to array element | +| ContainerLengthCmpOffByOne.cs:8:25:8:40 | ... <= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:10:31:10:37 | access to array element | access to array element | +| ContainerLengthCmpOffByOne.cs:14:25:14:40 | ... >= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:16:31:16:37 | access to array element | access to array element | +| ContainerLengthCmpOffByOne.cs:27:13:27:28 | ... <= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:29:31:29:37 | access to array element | access to array element | +| ContainerLengthCmpOffByOne.cs:33:13:33:28 | ... >= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:35:31:35:37 | access to array element | access to array element | diff --git a/csharp/ql/test/query-tests/Likely Bugs/UncheckedCastInEquals/UncheckedCastInEquals.expected b/csharp/ql/test/query-tests/Likely Bugs/UncheckedCastInEquals/UncheckedCastInEquals.expected index 2706724c429..f602c9fcd11 100644 --- a/csharp/ql/test/query-tests/Likely Bugs/UncheckedCastInEquals/UncheckedCastInEquals.expected +++ b/csharp/ql/test/query-tests/Likely Bugs/UncheckedCastInEquals/UncheckedCastInEquals.expected @@ -1 +1 @@ -| UncheckedCastInEquals.cs:7:17:7:27 | (...) ... | Missing type-check before casting parameter to 'Equals'. | +| UncheckedCastInEquals.cs:7:17:7:27 | (...) ... | Equals() method does not check argument type. | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-730/RegexInjection/RegexInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-730/RegexInjection/RegexInjection.expected index c9c2f544940..01b1dcfb67f 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-730/RegexInjection/RegexInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-730/RegexInjection/RegexInjection.expected @@ -8,4 +8,4 @@ nodes | RegexInjection.cs:14:19:14:23 | access to local variable regex | semmle.label | access to local variable regex | subpaths #select -| RegexInjection.cs:14:19:14:23 | access to local variable regex | RegexInjection.cs:10:24:10:46 | access to property QueryString : NameValueCollection | RegexInjection.cs:14:19:14:23 | access to local variable regex | $@ flows to the construction of a regular expression. | RegexInjection.cs:10:24:10:46 | access to property QueryString | User-provided value | +| RegexInjection.cs:14:19:14:23 | access to local variable regex | RegexInjection.cs:10:24:10:46 | access to property QueryString : NameValueCollection | RegexInjection.cs:14:19:14:23 | access to local variable regex | This regular expression is constructed from a $@. | RegexInjection.cs:10:24:10:46 | access to property QueryString | user-provided value | diff --git a/csharp/ql/test/query-tests/Useless Code/RedundantToStringCall/RedundantToStringCall.expected b/csharp/ql/test/query-tests/Useless Code/RedundantToStringCall/RedundantToStringCall.expected index f6e2f4d87fd..8021c21df2a 100644 --- a/csharp/ql/test/query-tests/Useless Code/RedundantToStringCall/RedundantToStringCall.expected +++ b/csharp/ql/test/query-tests/Useless Code/RedundantToStringCall/RedundantToStringCall.expected @@ -1,3 +1,3 @@ -| RedundantToStringCall.cs:7:27:7:38 | call to method ToString | Redundant call to 'ToString'. | -| RedundantToStringCall.cs:10:37:10:48 | call to method ToString | Redundant call to 'ToString'. | -| RedundantToStringCallBad.cs:7:45:7:56 | call to method ToString | Redundant call to 'ToString'. | +| RedundantToStringCall.cs:7:27:7:38 | call to method ToString | Redundant call to 'ToString' on a String object. | +| RedundantToStringCall.cs:10:37:10:48 | call to method ToString | Redundant call to 'ToString' on a String object. | +| RedundantToStringCallBad.cs:7:45:7:56 | call to method ToString | Redundant call to 'ToString' on a String object. | diff --git a/csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.expected similarity index 82% rename from csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.expected index 8d2b9dcb1d3..da1be111a39 100644 --- a/csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.expected @@ -1,5 +1,8 @@ | NoSummaries;BaseClass;M1;(System.String);generated | | NoSummaries;BaseClass;M2;(System.String);generated | +| NoSummaries;CollectionFlow;ReturnSimpleTypeArray;(System.Int32[]);generated | +| NoSummaries;CollectionFlow;ReturnSimpleTypeDictionary;(System.Collections.Generic.Dictionary);generated | +| NoSummaries;CollectionFlow;ReturnSimpleTypeList;(System.Collections.Generic.List);generated | | NoSummaries;EquatableBound;Equals;(System.Object);generated | | NoSummaries;EquatableUnBound<>;Equals;(T);generated | | NoSummaries;SimpleTypes;M1;(System.Boolean);generated | diff --git a/csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSinkModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSinkModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureSinkModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSinkModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSourceModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSourceModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureSourceModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSourceModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSummaryModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected similarity index 84% rename from csharp/ql/test/utils/model-generator/CaptureSummaryModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected index 23c7bff2ce4..61f41df45c5 100644 --- a/csharp/ql/test/utils/model-generator/CaptureSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected @@ -13,8 +13,13 @@ | Summaries;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this];Argument[0].Element;taint;generated | | Summaries;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;taint;generated | | Summaries;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;taint;generated | +| Summaries;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;generated | +| Summaries;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;generated | +| Summaries;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0].Element;ReturnValue;taint;generated | | Summaries;CollectionFlow;false;ReturnFieldInAList;();;Argument[this];ReturnValue;taint;generated | | Summaries;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;generated | +| Summaries;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;generated | +| Summaries;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;generated | | Summaries;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;taint;generated | | Summaries;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;taint;generated | | Summaries;DerivedClass2Flow;false;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;generated | diff --git a/csharp/ql/test/utils/model-generator/CaptureSummaryModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSummaryModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref diff --git a/csharp/ql/test/utils/model-generator/NoSummaries.cs b/csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs similarity index 80% rename from csharp/ql/test/utils/model-generator/NoSummaries.cs rename to csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs index 5d1f26574b0..112857f504e 100644 --- a/csharp/ql/test/utils/model-generator/NoSummaries.cs +++ b/csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace NoSummaries; @@ -110,4 +111,24 @@ public abstract class BaseClass // Negative summary. public abstract string M2(string s); +} + +// No methods in this class will have generated flow as +// the simple types used in the collection are not bulk data types. +public class CollectionFlow +{ + public int[] ReturnSimpleTypeArray(int[] a) + { + return a; + } + + public List ReturnSimpleTypeList(List a) + { + return a; + } + + public Dictionary ReturnSimpleTypeDictionary(Dictionary a) + { + return a; + } } \ No newline at end of file diff --git a/csharp/ql/test/utils/model-generator/Sinks.cs b/csharp/ql/test/utils/model-generator/dataflow/Sinks.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/Sinks.cs rename to csharp/ql/test/utils/model-generator/dataflow/Sinks.cs diff --git a/csharp/ql/test/utils/model-generator/Sources.cs b/csharp/ql/test/utils/model-generator/dataflow/Sources.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/Sources.cs rename to csharp/ql/test/utils/model-generator/dataflow/Sources.cs diff --git a/csharp/ql/test/utils/model-generator/Summaries.cs b/csharp/ql/test/utils/model-generator/dataflow/Summaries.cs similarity index 90% rename from csharp/ql/test/utils/model-generator/Summaries.cs rename to csharp/ql/test/utils/model-generator/dataflow/Summaries.cs index fe82980db9c..3db83726765 100644 --- a/csharp/ql/test/utils/model-generator/Summaries.cs +++ b/csharp/ql/test/utils/model-generator/dataflow/Summaries.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Collections; using System.Collections.Generic; namespace Summaries; @@ -85,6 +86,31 @@ public class CollectionFlow { return new List { tainted }; } + + public string[] ReturnComplexTypeArray(string[] a) + { + return a; + } + + public List ReturnBulkTypeList(List a) + { + return a; + } + + public Dictionary ReturnComplexTypeDictionary(Dictionary a) + { + return a; + } + + public Array ReturnUntypedArray(Array a) + { + return a; + } + + public IList ReturnUntypedList(IList a) + { + return a; + } } public class IEnumerableFlow @@ -233,4 +259,4 @@ public class EqualsGetHashCodeNoFlow { return intTainted; } -} \ No newline at end of file +} diff --git a/csharp/ql/test/utils/model-generator/options b/csharp/ql/test/utils/model-generator/dataflow/options similarity index 52% rename from csharp/ql/test/utils/model-generator/options rename to csharp/ql/test/utils/model-generator/dataflow/options index a55169c6e97..ed33eca5326 100644 --- a/csharp/ql/test/utils/model-generator/options +++ b/csharp/ql/test/utils/model-generator/dataflow/options @@ -1,2 +1,2 @@ semmle-extractor-options: /r:System.Linq.dll /r:System.Collections.Specialized.dll -semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs +semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected new file mode 100644 index 00000000000..6405ea3fab8 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected @@ -0,0 +1,165 @@ +| Summaries;IGrouping<,>;true;get_Key;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;IOrderedEnumerable<>;true;CreateOrderedEnumerable<>;(System.Func,System.Collections.Generic.IComparer,System.Boolean);;Argument[this].Element;Argument[0].Parameter[0];value;generated | +| Summaries;IOrderedEnumerable<>;true;CreateOrderedEnumerable<>;(System.Func,System.Collections.Generic.IComparer,System.Boolean);;Argument[this].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[0].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[1];Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[1];Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[2].ReturnValue;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[2].ReturnValue;Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[3].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[0].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[1];Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[2].ReturnValue;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[2].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;Argument[1].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;All<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Any<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Append<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Append<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;AsEnumerable<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Average<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Concat<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Concat<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Count<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Distinct<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DistinctBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;DistinctBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ElementAt<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;ElementAtOrDefault<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Intersect<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Intersect<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;IntersectBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;IntersectBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[0].Element;Argument[4].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[1].Element;Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[1].Element;Argument[4].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[4].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LongCount<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Max<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Max<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Max<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Max<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MaxBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MaxBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Min<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Min<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Min<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;MinBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MinBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;OrderBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;OrderBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;OrderByDescending<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;OrderByDescending<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Prepend<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Prepend<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Repeat<>;(TResult,System.Int32);;Argument[0];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Reverse<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Select<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Select<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[1].ReturnValue.Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[2].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,>;(System.Collections.Generic.IEnumerable,System.Func>);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,>;(System.Collections.Generic.IEnumerable,System.Func>);;Argument[1].ReturnValue.Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Skip<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SkipLast<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SkipWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SkipWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Take<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;TakeLast<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;TakeWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;TakeWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ThenBy<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;ThenBy<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ThenByDescending<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;ThenByDescending<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ToHashSet<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ToList<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Union<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Union<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Where<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Where<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[2].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;TypeBasedCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | +| Summaries;TypeBasedCollection<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | +| Summaries;TypeBasedCollection<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | +| Summaries;TypeBasedCollection<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedCollection<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | +| Summaries;TypeBasedComplex<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<,>;(T1,System.Func);;Argument[0];Argument[1].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<,>;(T1,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap<>;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap<>;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;GetMany;();;Argument[this].SyntheticField[ArgType0];ReturnValue.Element;value;generated | +| Summaries;TypeBasedComplex<>;false;Map<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Map<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;MapComplex<>;(System.Func);;Argument[0].ReturnValue;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;MapComplex<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Set;(System.Int32,System.Func);;Argument[1].ReturnValue;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedNoCollection<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedNoCollection<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id<>;(S);;Argument[0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;TypeBasedSimple;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;get_Prop;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref new file mode 100644 index 00000000000..99c0975a4c2 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref @@ -0,0 +1 @@ +utils/model-generator/CaptureTypeBasedSummaryModels.ql \ No newline at end of file diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs new file mode 100644 index 00000000000..f87563b945d --- /dev/null +++ b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs @@ -0,0 +1,210 @@ +using System; +using System.Linq; +using System.Collections; +using System.Collections.Generic; + +namespace Summaries; + +public class TypeBasedSimple { + + public T Prop { + get { throw null; } + set { throw null; } + } + + public TypeBasedSimple(T t) { throw null; } + + public T Get() { throw null; } + + public T Get(object x) { throw null; } + + public T Id(T x) { throw null; } + + public S Id(S x) { throw null; } + + public void Set(T x) { throw null; } + + public void Set(int x, T y) { throw null; } + + public void Set(S x) { throw null; } // No summary as S is unrelated to T +} + +public class TypeBasedComplex { + + public void AddMany(IEnumerable xs) { throw null; } + + public int Apply(Func f) { throw null; } + + public S Apply(Func f) { throw null; } + + public T2 Apply(T1 x, Func f) { throw null; } + + public TypeBasedComplex FlatMap(Func> f) { throw null; } + + public TypeBasedComplex FlatMap(Func> f) { throw null; } + + public IList GetMany() { throw null; } + + public S Map(Func f) { throw null; } + + public TypeBasedComplex MapComplex(Func f) { throw null; } + + public TypeBasedComplex Return(Func> f) { throw null; } + + public void Set(int x, Func f) { throw null;} +} + +// It is assumed that this is a collection with elements of type T. +public class TypeBasedCollection : IEnumerable { + IEnumerator IEnumerable.GetEnumerator() { throw null; } + IEnumerator IEnumerable.GetEnumerator() { throw null; } + + public void Add(T x) { throw null; } + + public void AddMany(IEnumerable x) { throw null; } + + public T First() { throw null; } + + public ICollection GetMany() { throw null; } +} + +// It is assumed that this is NOT a collection with elements of type T. +public class TypeBasedNoCollection : IEnumerable { + IEnumerator IEnumerable.GetEnumerator() { throw null; } + + public T Get() { throw null; } + + public void Set(T x) { throw null; } +} + +/* + * Representative subset of Linq. + * + * Only methods that will get summaries generated correctly are commented in. + * The remaning methods and interfaces are commented out with a descriptive reason. + * In some cases we will not be able correctly generate a summary based purely on the + * type information. + */ +public static class SystemLinqEnumerable { + + public static TSource Aggregate(this IEnumerable source, Func func) { throw null; } + public static TAccumulate Aggregate(this IEnumerable source, TAccumulate seed, Func func) { throw null; } + public static TResult Aggregate(this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) { throw null; } + public static bool All(this IEnumerable source, Func predicate) { throw null; } + public static bool Any(this IEnumerable source) { throw null; } + public static bool Any(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Append(this IEnumerable source, TSource element) { throw null; } + public static IEnumerable AsEnumerable(this IEnumerable source) { throw null; } + public static decimal Average(this IEnumerable source, Func selector) { throw null; } + // Summary will not be derivables based on type information. + // public static IEnumerable Cast(this IEnumerable source) { throw null; } + public static IEnumerable Chunk(this IEnumerable source, int size) { throw null; } + public static IEnumerable Concat(this IEnumerable first, IEnumerable second) { throw null; } + public static bool Contains(this IEnumerable source, TSource value) { throw null; } + public static int Count(this IEnumerable source) { throw null; } + public static int Count(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable DefaultIfEmpty(this IEnumerable source) { throw null; } + public static IEnumerable DefaultIfEmpty(this IEnumerable source, TSource defaultValue) { throw null; } + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { throw null; } + public static IEnumerable Distinct(this IEnumerable source) { throw null; } + public static TSource? ElementAtOrDefault(this IEnumerable source, int index) { throw null; } + public static TSource ElementAt(this IEnumerable source, int index) { throw null; } + public static IEnumerable Empty() { throw null; } + // These summaries will not be derivable based on type information. + // public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + // public static IEnumerable Except(this IEnumerable first, IEnumerable second) { throw null; } + public static TSource? FirstOrDefault(this IEnumerable source) { throw null; } + public static TSource FirstOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? FirstOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information. + // public static TSource FirstOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource First(this IEnumerable source) { throw null; } + public static TSource First(this IEnumerable source, Func predicate) { throw null; } + // Missing summary for Argument[0].Element -> Argument[2].Parameter[1].Element and similar problem for GroupJoin (issue with generator) + // public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector) { throw null; } + // public static IEnumerable GroupJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) { throw null; } + public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + public static IEnumerable Intersect(this IEnumerable first, IEnumerable second) { throw null; } + public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) { throw null; } + public static TSource? LastOrDefault(this IEnumerable source) { throw null; } + public static TSource LastOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? LastOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information (same problem as for FirstOrDefault) + // public static TSource LastOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource Last(this IEnumerable source) { throw null; } + public static TSource Last(this IEnumerable source, Func predicate) { throw null; } + public static long LongCount(this IEnumerable source, Func predicate) { throw null; } + public static TSource? MaxBy(this IEnumerable source, Func keySelector) { throw null; } + public static TSource? Max(this IEnumerable source) { throw null; } + public static decimal Max(this IEnumerable source, Func selector) { throw null; } + public static TResult? Max(this IEnumerable source, Func selector) { throw null; } + public static TSource? MinBy(this IEnumerable source, Func keySelector) { throw null; } + public static TSource? Min(this IEnumerable source) { throw null; } + public static TResult? Min(this IEnumerable source, Func selector) { throw null; } + // These summaries will not be derivable based on type information. + // public static IEnumerable OfType(this IEnumerable source) { throw null; } + public static IOrderedEnumerable OrderByDescending(this IEnumerable source, Func keySelector) { throw null; } + public static IOrderedEnumerable OrderBy(this IEnumerable source, Func keySelector) { throw null; } + public static IEnumerable Prepend(this IEnumerable source, TSource element) { throw null; } + public static IEnumerable Repeat(TResult element, int count) { throw null; } + public static IEnumerable Reverse(this IEnumerable source) { throw null; } + public static IEnumerable SelectMany(this IEnumerable source, Func> selector) { throw null; } + public static IEnumerable SelectMany(this IEnumerable source, Func> collectionSelector, Func resultSelector) { throw null; } + public static IEnumerable Select(this IEnumerable source, Func selector) { throw null; } + public static bool SequenceEqual(this IEnumerable first, IEnumerable second) { throw null; } + public static TSource? SingleOrDefault(this IEnumerable source) { throw null; } + public static TSource SingleOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? SingleOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information (same problem as for FirstOrDefault) + // public static TSource SingleOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource Single(this IEnumerable source) { throw null; } + public static TSource Single(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable SkipLast(this IEnumerable source, int count) { throw null; } + public static IEnumerable SkipWhile(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Skip(this IEnumerable source, int count) { throw null; } + public static IEnumerable TakeLast(this IEnumerable source, int count) { throw null; } + public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Take(this IEnumerable source, int count) { throw null; } + public static IOrderedEnumerable ThenByDescending(this IOrderedEnumerable source, Func keySelector) { throw null; } + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, Func keySelector) { throw null; } + // Missing summary for Argument[0].Element -> ReturnValue.Element (issue with generator) + // public static TSource[] ToArray(this IEnumerable source) { throw null; } + // Summaries related to dictionaries is not generated correctly as dictionaries are not identified as collections of keys and values (issue with generator). + // public static Dictionary ToDictionary(this IEnumerable source, Func keySelector) where TKey : notnull { throw null; } + // public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { throw null; } + public static HashSet ToHashSet(this IEnumerable source) { throw null; } + public static List ToList(this IEnumerable source) { throw null; } + // Type to complicated to be handled by the generator (issue with generator). + // public static ILookup ToLookup(this IEnumerable source, Func keySelector) { throw null; } + // public static ILookup ToLookup(this IEnumerable source, Func keySelector, Func elementSelector) { throw null; } + public static IEnumerable UnionBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + public static IEnumerable Union(this IEnumerable first, IEnumerable second) { throw null; } + public static IEnumerable Where(this IEnumerable source, Func predicate) { throw null; } + // Type to complicated to be handled by the generator (issue with generator). + // public static IEnumerable<(TFirst First, TSecond Second)> Zip(this IEnumerable first, IEnumerable second) { throw null; } + // public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip(this IEnumerable first, IEnumerable second, IEnumerable third) { throw null; } + public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func resultSelector) { throw null; } +} + +public interface IGrouping : IEnumerable, IEnumerable { + TKey Key { get; } +} + +// public interface ILookup : IEnumerable>, IEnumerable { +// IEnumerable this[TKey key] { get; } +// bool Contains(TKey key); +// } + +public interface IOrderedEnumerable : IEnumerable, IEnumerable { + IOrderedEnumerable CreateOrderedEnumerable(Func keySelector, IComparer? comparer, bool descending); +} + +// public partial class Lookup : IEnumerable>, IEnumerable, ILookup{ +// internal Lookup() { } +// public int Count { get { throw null; } } +// public IEnumerable this[TKey key] { get { throw null; } } +// public IEnumerable ApplyResultSelector(Func, TResult> resultSelector) { throw null; } +// public bool Contains(TKey key) { throw null; } +// public IEnumerator> GetEnumerator() { throw null; } +// IEnumerator IEnumerable.GetEnumerator() { throw null; } +// } diff --git a/csharp/tools/linux64/compiler-tracing.spec b/csharp/tools/linux64/compiler-tracing.spec deleted file mode 100644 index 659170b7ceb..00000000000 --- a/csharp/tools/linux64/compiler-tracing.spec +++ /dev/null @@ -1,16 +0,0 @@ -**/mcs.exe: -**/csc.exe: - invoke ${config_dir}/Semmle.Extraction.CSharp.Driver - prepend --compiler - prepend "${compiler}" - prepend --cil -**/mono*: -**/dotnet: - invoke ${config_dir}/Semmle.Extraction.CSharp.Driver - prepend --dotnetexec - prepend --cil -**/msbuild: -**/xbuild: - replace yes - invoke ${compiler} - append /p:UseSharedCompilation=false diff --git a/csharp/tools/osx64/compiler-tracing.spec b/csharp/tools/osx64/compiler-tracing.spec deleted file mode 100644 index 659170b7ceb..00000000000 --- a/csharp/tools/osx64/compiler-tracing.spec +++ /dev/null @@ -1,16 +0,0 @@ -**/mcs.exe: -**/csc.exe: - invoke ${config_dir}/Semmle.Extraction.CSharp.Driver - prepend --compiler - prepend "${compiler}" - prepend --cil -**/mono*: -**/dotnet: - invoke ${config_dir}/Semmle.Extraction.CSharp.Driver - prepend --dotnetexec - prepend --cil -**/msbuild: -**/xbuild: - replace yes - invoke ${compiler} - append /p:UseSharedCompilation=false diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 03d1e49699a..7c62f0062e4 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -1,7 +1,9 @@ function RegisterExtractorPack(id) - local extractor = GetPlatformToolsDirectory() .. - 'Semmle.Extraction.CSharp.Driver' - if OperatingSystem == 'windows' then extractor = extractor .. '.exe' end + function Exify(path) + if OperatingSystem == 'windows' then return path .. '.exe' else return path end + end + + local extractor = Exify(GetPlatformToolsDirectory() .. 'Semmle.Extraction.CSharp.Driver') function DotnetMatcherBuild(compilerName, compilerPath, compilerArguments, _languageId) @@ -47,10 +49,30 @@ function RegisterExtractorPack(id) return nil end + function MsBuildMatcher(compilerName, compilerPath, compilerArguments, _languageId) + if MatchCompilerName('^' .. Exify('msbuild') .. '$', compilerName, compilerPath, + compilerArguments) or + MatchCompilerName('^' .. Exify('xbuild') .. '$', compilerName, compilerPath, + compilerArguments) then + return { + order = ORDER_REPLACE, + invocation = BuildExtractorInvocation(id, compilerPath, + compilerPath, + compilerArguments, + nil, { + '/p:UseSharedCompilation=false', + '/p:MvcBuildViews=true' + }) + + } + end + end + local windowsMatchers = { DotnetMatcherBuild, + MsBuildMatcher, CreatePatternMatcher({ '^csc.*%.exe$' }, MatchCompilerName, extractor, { - prepend = { '--cil', '--compiler', '"${compiler}"' }, + prepend = { '--compiler', '"${compiler}"' }, order = ORDER_BEFORE }), CreatePatternMatcher({ '^fakes.*%.exe$', 'moles.*%.exe' }, @@ -63,7 +85,7 @@ function RegisterExtractorPack(id) local seenCompilerCall = false local argv = NativeArgumentsToArgv(compilerArguments.nativeArgumentPointer) - local extractorArgs = { '--cil', '--compiler' } + local extractorArgs = { '--compiler' } for _, arg in ipairs(argv) do if arg:match('csc%.dll$') then seenCompilerCall = true @@ -91,25 +113,11 @@ function RegisterExtractorPack(id) DotnetMatcherBuild, CreatePatternMatcher({ '^mcs%.exe$', '^csc%.exe$' }, MatchCompilerName, extractor, { - prepend = { '--cil', '--compiler', '"${compiler}"' }, + prepend = { '--compiler', '"${compiler}"' }, order = ORDER_BEFORE - }), function(compilerName, compilerPath, compilerArguments, _languageId) - if MatchCompilerName('^msbuild$', compilerName, compilerPath, - compilerArguments) or - MatchCompilerName('^xbuild$', compilerName, compilerPath, - compilerArguments) then - return { - order = ORDER_REPLACE, - invocation = BuildExtractorInvocation(id, compilerPath, - compilerPath, - compilerArguments, - nil, { - '/p:UseSharedCompilation=false' - }) - - } - end - end, function(compilerName, compilerPath, compilerArguments, _languageId) + }), + MsBuildMatcher, + function(compilerName, compilerPath, compilerArguments, _languageId) -- handle cases like `dotnet exec csc.dll ` and `mono(-sgen64) csc.exe ` if compilerName ~= 'dotnet' and not compilerName:match('^mono') then return nil @@ -117,7 +125,7 @@ function RegisterExtractorPack(id) local seenCompilerCall = false local argv = compilerArguments.argv - local extractorArgs = { '--cil', '--compiler' } + local extractorArgs = { '--compiler' } for _, arg in ipairs(argv) do if arg:match('csc%.dll$') or arg:match('csc%.exe$') or arg:match('mcs%.exe$') then seenCompilerCall = true diff --git a/csharp/tools/win64/compiler-tracing.spec b/csharp/tools/win64/compiler-tracing.spec deleted file mode 100644 index ca1d544e884..00000000000 --- a/csharp/tools/win64/compiler-tracing.spec +++ /dev/null @@ -1,13 +0,0 @@ -**\fakes*.exe: -**\moles*.exe: - order compiler - trace no -**\csc*.exe: - invoke ${config_dir}\Semmle.Extraction.CSharp.Driver.exe - prepend --compiler - prepend "${compiler}" - prepend --cil -**\dotnet.exe: - invoke ${config_dir}\Semmle.Extraction.CSharp.Driver.exe - prepend --dotnetexec - prepend --cil diff --git a/docs/codeql/codeql-cli/about-codeql-workspaces.rst b/docs/codeql/codeql-cli/about-codeql-workspaces.rst index f5b477ec2c0..860fbdb7d63 100644 --- a/docs/codeql/codeql-cli/about-codeql-workspaces.rst +++ b/docs/codeql/codeql-cli/about-codeql-workspaces.rst @@ -1,6 +1,6 @@ .. _about-codeql-workspaces: -About CodeQL Workspaces +About CodeQL workspaces ======================= .. include:: ../reusables/beta-note-package-management.rst @@ -20,7 +20,7 @@ A CodeQL workspace is defined by a ``codeql-workspace.yml`` yaml file. This file * The ``ignore`` block contains a list of glob patterns that define CodeQL packs that are not available in the workspace. * The ``registries`` block contains a list of GHES URLs and package patterns that control which container registry is used for publishing CodeQL packs. For more information, see :ref:`Working with CodeQL packs on GitHub Enterprise Server `. -Each entry in the ``provide`` or ``ignore`` section must map to the location of a ``qlpack.yml`` file. All glob patterns are defined relative to the directory that contains the workspace file. For a list of patterns accepted in this file, see" `@actions/glob `__ . +Each entry in the ``provide`` or ``ignore`` section must map to the location of a ``qlpack.yml`` file. All glob patterns are defined relative to the directory that contains the workspace file. For a list of patterns accepted in this file, see "`@actions/glob `__ ." For example, the following ``codeql-workspace.yml`` file defines a workspace that contains all the CodeQL packs recursively found in the ``codeql-packs`` directory, except for the packs in the ``experimental`` directory. The ``registries`` block specifies that ``codeql/*`` packs should be downloaded from https://ghcr.io/v2/, which is GitHub's default container registry. All other packs should be downloaded from and published to the regsitry at ``GHE_HOSTNAME``. @@ -55,7 +55,7 @@ This is particularly useful in the following situations: CodeQL workspaces and query resolution -------------------------------------- -All CodeQL packs in a workspace are available as source dependencies for each other when you run any CodeQL command that resolves queries or packs. For example, when you run ``codeql pack install`` in a pack directory in a workspace, any dependency that can be found in the workspace will be used instead of downloading that dependency to the package cache and adding it to the ``codeql-pack.lock.yml`` file. For more information, see ":ref:Adding and Installing Dependencies `." +All CodeQL packs in a workspace are available as source dependencies for each other when you run any CodeQL command that resolves queries or packs. For example, when you run ``codeql pack install`` in a pack directory in a workspace, any dependency that can be found in the workspace will be used instead of downloading that dependency to the package cache and adding it to the ``codeql-pack.lock.yml`` file. For more information, see ":ref:`Adding and Installing Dependencies `." Similarly, when you publish a CodeQL query pack to the GitHub container registry using ``codeql pack publish`` the command will always use the dependencies from the workspace instead of using dependencies found in the local package cache. diff --git a/docs/codeql/codeql-cli/about-ql-packs.rst b/docs/codeql/codeql-cli/about-ql-packs.rst new file mode 100644 index 00000000000..2f8d4d9229d --- /dev/null +++ b/docs/codeql/codeql-cli/about-ql-packs.rst @@ -0,0 +1,12 @@ +.. _about-ql-packs: + +About QL packs +============== + +This page has been moved to ":doc:`About CodeQL packs `." + + +.. toctree:: + :hidden: + + about-ql-packs diff --git a/docs/codeql/codeql-cli/creating-codeql-databases.rst b/docs/codeql/codeql-cli/creating-codeql-databases.rst index 5a8e33ffae6..484163d94e7 100644 --- a/docs/codeql/codeql-cli/creating-codeql-databases.rst +++ b/docs/codeql/codeql-cli/creating-codeql-databases.rst @@ -11,11 +11,11 @@ or download them from GitHub.com. CodeQL analysis relies on extracting relational data from your code, and using it to build a :ref:`CodeQL database `. CodeQL databases contain all of the important information about a codebase, which can -be analyzed by executing CodeQL queries against it. GitHub creates and +be analyzed by executing CodeQL queries against it. GitHub creates and stores CodeQL databases for a large number of open-source projects. For more information, see ":ref:`Downloading CodeQL databases from GitHub.com `." -You can also create CodeQL databases yourself using the CodeQL CLI. +You can also create CodeQL databases yourself using the CodeQL CLI. Before you generate a CodeQL database, you need to: - Install and set up the CodeQL CLI. For more information, see @@ -214,10 +214,10 @@ commands that you can specify for compiled languages. codeql database create cpp-database --language=cpp --command=make -- C# project built using ``dotnet build``:: +- C# project built using ``dotnet build``: - It is a good idea to add `/t:rebuild` to ensure that all code will be built, or do a - prior `dotnet clean` (code that is not built will not be included in the CodeQL database): + It is a good idea to add `/t:rebuild` to ensure that all code will be built, or do a + prior `dotnet clean` (code that is not built will not be included in the CodeQL database):: codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild' @@ -391,9 +391,9 @@ Downloading databases from GitHub.com ------------------------------------- .. include:: ../reusables/download-github-database.rst - + Before running an analysis with the CodeQL CLI, you must unzip the databases. - + Further reading --------------- diff --git a/docs/codeql/codeql-overview/codeql-tools.rst b/docs/codeql/codeql-overview/codeql-tools.rst index c51a5286cb0..78f47200c94 100644 --- a/docs/codeql/codeql-overview/codeql-tools.rst +++ b/docs/codeql/codeql-overview/codeql-tools.rst @@ -13,9 +13,40 @@ CodeQL command-line interface The CodeQL command-line interface (CLI) is primarily used to create databases for security research. You can also query CodeQL databases directly from the command line -or using the Visual Studio Code extension. For more information, see -":ref:`CodeQL CLI `." +or using the Visual Studio Code extension. +The CodeQL CLI can be downloaded from `GitHub releases `__. +For more information, see ":ref:`CodeQL CLI `" and the `CLI changelog `__. +CodeQL packs +----------------------------- + +The standard CodeQL query and library packs +(`source `__) +maintained by GitHub are: + +- ``codeql/cpp-queries`` (`changelog `__, `source `__) +- ``codeql/cpp-all`` (`changelog `__, `source `__) +- ``codeql/csharp-queries`` (`changelog `__, `source `__) +- ``codeql/csharp-all`` (`changelog `__, `source `__) +- ``codeql/go-queries`` (`changelog `__, `source `__) +- ``codeql/go-all`` (`changelog `__, `source `__) +- ``codeql/java-queries`` (`changelog `__, `source `__) +- ``codeql/java-all`` (`changelog `__, `source `__) +- ``codeql/javascript-queries`` (`changelog `__, `source `__) +- ``codeql/javascript-all`` (`changelog `__, `source `__) +- ``codeql/python-queries`` (`changelog `__, `source `__) +- ``codeql/python-all`` (`changelog `__, `source `__) +- ``codeql/ruby-queries`` (`changelog `__, `source `__) +- ``codeql/ruby-all`` (`changelog `__, `source `__) + +For more information, see ":ref:`About CodeQL packs `." + +CodeQL bundle +----------------------------- + +The CodeQL bundle consists of the CodeQL CLI together with the standard CodeQL query and library packs +maintained by GitHub. The bundle can be downloaded from `GitHub releases `__. +Use this when running `code scanning with CodeQL `__ on GitHub Actions or in another CI system. CodeQL for Visual Studio Code ----------------------------- diff --git a/docs/codeql/ql-language-reference/index.rst b/docs/codeql/ql-language-reference/index.rst index 5a971259cf7..cf1926ae3d0 100644 --- a/docs/codeql/ql-language-reference/index.rst +++ b/docs/codeql/ql-language-reference/index.rst @@ -15,6 +15,8 @@ Learn all about QL, the powerful query language that underlies the code scanning - :doc:`Modules `: Modules provide a way of organizing QL code by grouping together related types, predicates, and other modules. +- :doc:`Signatures `: Signatures provide a typing mechanism to parameters of parameterized modules. + - :doc:`Aliases `: An alias is an alternative name for an existing QL entity. - :doc:`Variables `: Variables in QL are used in a similar way to variables in algebra or logic. They represent sets of values, and those values are usually restricted by a formula. @@ -44,6 +46,7 @@ Learn all about QL, the powerful query language that underlies the code scanning queries types modules + signatures aliases variables expressions diff --git a/docs/codeql/ql-language-reference/modules.rst b/docs/codeql/ql-language-reference/modules.rst index b9998b63248..b82ea1c2838 100644 --- a/docs/codeql/ql-language-reference/modules.rst +++ b/docs/codeql/ql-language-reference/modules.rst @@ -133,6 +133,92 @@ defined :ref:`above `: This defines an explicit module named ``M``. The body of this module defines the class ``OneTwo``. +.. _parameterized-modules: + +Parameterized modules +===================== + +Parameterized modules are QL's approach to generic programming. +Similar to explicit modules, parameterized modules are defined within other modules using the keywork ``module``. +In addition to the module name, parameterized modules declare one or more parameters between the name and the module body. + +For example, consider the module ``M``, which takes two predicate parameters and defines a new predicate +that applies them one after the other: + +.. code-block:: ql + + module M { + bindingset[x] + int applyBoth(int x) { + result = second(first(x)) + } + } + +Parameterized modules cannot be directly referenced. +Instead, you instantiate a parameterized module by passing arguments enclosed in angle brackets (``<`` and ``>``) to the module. +Instantiated parameterized modules can be used as a :ref:`module expression `, identical to explicit module references. + +For example, we can instantiate ``M`` with two identical arguments ``increment``, creating a module +containing a predicate that adds 2: + +.. code-block:: ql + + bindingset[result] bindingset[x] + int increment(int x) { result = x + 1 } + + module IncrementTwice = M; + + select IncrementTwice::applyBoth(40) // 42 + +The parameters of a parameterized module are (meta-)typed with :ref:`signatures `. + +For example, in the previous two snippets, we relied on the predicate signature ``transformer``: + +.. code-block:: ql + + bindingset[x] + signature int transformer(int x); + +The instantiation of parameterized modules is applicative. +That is, if you instantiate a parameterized module twice with identical arguments, the resulting object is the same. +This is particularly relevant for type definitions inside parameterized modules as :ref:`classes ` +or via :ref:`newtype `, because the duplication of such type definitions would result in +incompatible types. + +The following example instantiates module ``M`` inside calls to predicate ``foo`` twice. +The first call is valid but the second call generates an error. + +.. code-block:: ql + + bindingset[this] + signature class TSig; + + module M { + newtype A = B() or C() + } + + string foo(M::A a) { ... } + + select foo(M::B()), // valid: repeated identical instantiation of M does not duplicate A, B, C + foo(M::B()) // ERROR: M::B is not compatible with M::A + +Module parameters are dependently typed, meaning that signature expressions in parameter definitions can reference +preceding parameters. + +For example, we can declare the signature for ``T2`` dependent on ``T1``, enforcing a subtyping relationship +between the two parameters: + +.. code-block:: ql + + signature class TSig; + + module Extends { signature class Type extends T; } + + module ParameterizedModule::Type T2> { ... } + +Dependently typed parameters are particularly useful in combination with +:ref:`parameterized module signatures `. + .. _module-bodies: Module bodies diff --git a/docs/codeql/ql-language-reference/name-resolution.rst b/docs/codeql/ql-language-reference/name-resolution.rst index c8fc351cffb..c14147d533e 100644 --- a/docs/codeql/ql-language-reference/name-resolution.rst +++ b/docs/codeql/ql-language-reference/name-resolution.rst @@ -21,7 +21,7 @@ In summary, the kinds of expressions are: - **Module expressions** - These refer to modules. - They can be simple :ref:`names `, :ref:`qualified references ` - (in import statements), or :ref:`selections `. + (in import statements), :ref:`selections `, or :ref:`instantiations `. - **Type expressions** - These refer to types. - They can be simple :ref:`names ` or :ref:`selections `. diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index ea90ebbf843..45747ae86ab 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -57,44 +57,27 @@ construction of the library path. First, determine the *query directory* of the ``.ql`` file being compiled. Starting with the directory containing the ``.ql`` file, and walking up the directory structure, each directory is checked for a -file called ``queries.xml`` or ``qlpack.yml``. The first directory +file called ``qlpack.yml`` or ``codeql-pack.yml``. The first directory where such a file is found is the query directory. If there is no such directory, the directory of the ``.ql`` file itself is the query directory. -A ``queries.xml`` file that defines a query directory must always -contain a single top-level tag named -``queries``, which has a ``language`` attribute set to the identifier -of the active database schema (for example, ````). - A ``qlpack.yml`` file defines a :ref:`CodeQL pack `. The content of a ``qlpack.yml`` file is described in the CodeQL CLI documentation. +``codeql-pack.yml`` is an alias for ``qlpack.yml``. -If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same -directory, the latter takes precedence (and the former is assumed to -exist for compatibility with older tooling). - -The CodeQL CLI and newer tools based on it (such as, +The CodeQL CLI and tools based on it (such as, GitHub code scanning and the CodeQL extension for Visual Studio Code) construct a library path using CodeQL packs. For each CodeQL pack added to the library path, the CodeQL packs named in its -``libraryPathDependencies`` will be subsequently added to the library +``dependencies`` will be subsequently added to the library path, and the process continues until all packs have been resolved. The actual library path consists of the root directories of the selected CodeQL packs. This process depends on a mechanism for finding -CodeQL packs by pack name, as described in the :ref:`CodeQL CLI documentation `. +CodeQL packs by pack name and version, as described in the :ref:`CodeQL CLI documentation `. -When the query directory contains a ``queries.xml`` file but no -``qlpack.yml``, the CodeQL pack resolution behaves as if it defines a QL -pack with no name and a single library path dependency named -``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from -``queries.xml``. The ``github/codeql`` repository provides packs with -names following this pattern, which themselves depend on the actual -CodeQL libraries for each language. - -When the query directory contains neither a ``queries.xml`` nor -``qlpack.yml`` file, it is considered to be a CodeQL pack with no name and +When the query directory contains neither a ``qlpack.yml`` nor +``codeql-pack.yml`` file, it is considered to be a CodeQL pack with no name and no library dependencies. This causes the library path to consist of *only* the query directory itself. This is not generally useful, but it suffices for running toy examples of QL code that don't @@ -160,7 +143,7 @@ Module definitions A QL module definition has the following syntax: -:: +:: module ::= annotation* "module" modulename "{" moduleBody "}" @@ -196,7 +179,7 @@ An import directive refers to a module identifier: import ::= annotations "import" importModuleId ("as" modulename)? - qualId ::= simpleId | qualId "." simpleId + qualId ::= simpleId | qualId "." simpleId importModuleId ::= qualId | importModuleId "::" simpleId @@ -268,7 +251,7 @@ With the exception of class domain types and character types (which cannot be re type ::= (moduleId "::")? classname | dbasetype | "boolean" | "date" | "float" | "int" | "string" - moduleId ::= simpleId | moduleId "::" simpleId + moduleId ::= simpleId | moduleId "::" simpleId A type reference is resolved to a type as follows: @@ -598,7 +581,7 @@ An integer literal is a possibly negated sequence of decimal digits (``0`` throu 0 42 123 - -2147483648 + -2147483648 Float literals (float) ~~~~~~~~~~~~~~~~~~~~~~ @@ -760,7 +743,7 @@ it is parsed as part of the first declaration. Inheriting QLDoc ~~~~~~~~~~~~~~~~ -If no QLDoc is provided then it may be inherited. +If no QLDoc is provided then it may be inherited. In the case of an alias then it may be inherited from the right-hand side of the alias. @@ -818,7 +801,7 @@ The body of a predicate is of one of three forms: :: optbody ::= ";" - | "{" formula "}" + | "{" formula "}" | "=" literalId "(" (predicateRef "/" int ("," predicateRef "/" int)*)? ")" "(" (exprs)? ")" In the first form, with just a semicolon, the predicate is said to not have a body. In the second form, the body of the predicate is the given formula (see "`Formulas <#formulas>`__"). In the third form, the body is a higher-order relation. @@ -873,7 +856,7 @@ Each member of a class is either a *character*, a predicate, or a field: :: member ::= character | predicate | field - character ::= qldoc? annotations classname "(" ")" "{" formula "}" + character ::= qldoc? annotations classname "(" ")" "{" formula "}" field ::= qldoc? annotations var_decl ";" Characters @@ -924,7 +907,7 @@ A valid class may not inherit from two different classes that include a field wi A valid field must override another field if it is annotated ``override``. -When field ``f`` overrides field ``g`` the type of ``f`` must be a subtype of the type of ``g``. ``f`` may not be a final field. +When field ``f`` overrides field ``g`` the type of ``f`` must be a subtype of the type of ``g``. ``f`` may not be a final field. Select clauses ~~~~~~~~~~~~~~ @@ -993,8 +976,8 @@ There are several kinds of expressions: | binop | cast | primary - - primary ::= eparen + + primary ::= eparen | literal | variable | super_expr @@ -1103,7 +1086,7 @@ A super expression has the following syntax: :: - super_expr ::= "super" | type "." "super" + super_expr ::= "super" | type "." "super" For a super expression to be valid, the ``this`` keyword must have a type and value in the typing environment. The type of the expression is the same as the type of ``this`` in the typing environment. @@ -1163,11 +1146,11 @@ A valid call with results *resolves* to a set of predicates. The ways a call can - If the call has no receiver and the predicate name is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__"). The identifier is then resolved in the exported predicate environment of the qualifier module. - If the call has a super expression as the receiver, then it resolves to a member predicate in a class that the enclosing class inherits from: - - If the super expression is unqualified and there is a single class that the current class inherits from, then the super-class is that class. + - If the super expression is unqualified and there is a single class that the current class inherits from, then the super-class is that class. - If the super expression is unqualified and there are multiple classes that the current class inherits from, then the super-class is the domain type. - - Otherwise, the super-class is the class named by the qualifier of the super expression. + - Otherwise, the super-class is the class named by the qualifier of the super expression. - The predicate is resolved by looking up its name and arity in the exported predicate environment of the super-class. + The predicate is resolved by looking up its name and arity in the exported predicate environment of the super-class. - If the type of the receiver is the same as the enclosing class, the predicate is resolved by looking up its name and arity in the visible predicate environment of the class. @@ -1226,15 +1209,15 @@ The rank expression must be present if the aggregate id is ``rank``; otherwise i Apart from the presence or absence of the rank variable, all other reduced forms of an aggregation are equivalent to a full form using the following steps: - If the formula is omitted, then it is taken to be ``any()``. -- If there are no aggregation expressions, then either: +- If there are no aggregation expressions, then either: - - The aggregation id is ``count`` or ``strictcount`` and the expression is taken to be ``1``. + - The aggregation id is ``count`` or ``strictcount`` and the expression is taken to be ``1``. - There must be precisely one variable declaration, and the aggregation expression is taken to be a reference to that variable. - If the aggregation id is ``concat`` or ``strictconcat`` and it has a single expression then the second expression is taken to be ``""``. -- If the ``monotonicAggregates`` language pragma is not enabled, or the original formula and variable declarations are both omitted, then the aggregate is transformed as follows: +- If the ``monotonicAggregates`` language pragma is not enabled, or the original formula and variable declarations are both omitted, then the aggregate is transformed as follows: - - For each aggregation expression ``expr_i``, a fresh variable ``v_i`` is declared with the same type as the expression in addition to the original variable declarations. + - For each aggregation expression ``expr_i``, a fresh variable ``v_i`` is declared with the same type as the expression in addition to the original variable declarations. - The new range is the conjunction of the original range and a term ``v_i = expr_i`` for each aggregation expression ``expr_i``. - Each original aggregation expression ``expr_i`` is replaced by a new aggregation expression ``v_i``. @@ -1320,11 +1303,11 @@ Expression pragmas can be used to guide optimization. The values of an expression pragma are the values of the contained expression. The type `only_bind_out` hints that uses of the result of the expression pragma should not be used to guide the evaluation of the result of the contained expression. -When checking to see that all values are bound the compiler does not assume that if the result of the expression pragma is bound then the result of the contained +When checking to see that all values are bound the compiler does not assume that if the result of the expression pragma is bound then the result of the contained expression is bound. The type `only_bind_into` hints that uses of the contained expression should not be used to guide the evaluation of the result of the expression pragma. -When checking to see that all values are bound the compiler does not assume that if the result of the contained expression is bound then the result of the +When checking to see that all values are bound the compiler does not assume that if the result of the contained expression is bound then the result of the expression pragma is bound. Ranges @@ -1498,7 +1481,7 @@ A comparison formula is two expressions separated by a comparison operator: :: comparison ::= expr compop expr - compop ::= "=" | "!=" | "<" | ">" | "<=" | ">=" + compop ::= "=" | "!=" | "<" | ">" | "<=" | ">=" A comparison formula matches if there is one value of the left expression that is in the given ordering with one of the values of the right expression. The ordering used is specified in "`Ordering <#ordering>`__." If one of the values is an integer and the other is a float value, then the integer is converted to a float value before the comparison. @@ -1582,7 +1565,7 @@ Aliases define new names for existing QL entities. alias ::= qldoc? annotations "predicate" literalId "=" predicateRef "/" int ";" | qldoc? annotations "class" classname "=" type ";" | qldoc? annotations "module" modulename "=" moduleId ";" - + An alias introduces a binding from the new name to the entity referred to by the right-hand side in the current module's declared predicate, type, or module environment respectively. @@ -1973,13 +1956,13 @@ Each layer of the stratification is *populated* in order. To populate a layer, e - To populate a predicate that has a formula as a body, find each named tuple ``t`` that has the following properties: - The tuple matches the body formula. - - The variables should be the predicate's arguments. + - The variables should be the predicate's arguments. - If the predicate has a result, then the tuples should additionally have a value for ``result``. - If the predicate is a member predicate or characteristic predicate of a class ``C`` then the tuples should additionally have a value for ``this`` and each visible field on the class. - The values corresponding to the arguments should all be a member of the declared types of the arguments. - The values corresponding to ``result`` should all be a member of the result type. - The values corresponding to the fields should all be a member of the declared types of the fields. - - If the predicate is a member predicate of a class ``C`` and not a characteristic predicate, then the tuples should additionally extend some tuple in ``C.class``. + - If the predicate is a member predicate of a class ``C`` and not a characteristic predicate, then the tuples should additionally extend some tuple in ``C.class``. - If the predicate is a characteristic predicate of a class ``C``, then there should be a tuple ``t'`` in ``C.extends`` such that for each visible field in ``C``, any field that is equal to or overrides a field in ``t'`` should have the same value in ``t``. ``this`` should also map to the same value in ``t`` and ``t'``. For each such tuple remove any components that correspond to fields and add it to the predicate in the store. @@ -1998,7 +1981,7 @@ Each layer of the stratification is *populated* in order. To populate a layer, e - To populate the type ``C.C`` for a class ``C``, if ``C`` has a characteristic predicate, then add all tuples from that predicate to the store. Otherwise add all tuples ``t`` such that: - - The variables of ``t`` should be ``this`` and the visible fields of ``C``. + - The variables of ``t`` should be ``this`` and the visible fields of ``C``. - The values corresponding to the fields should all be a member of the declared types of the fields. - If the predicate is a characteristic predicate of a class ``C``, then there should be a tuple ``t'`` in ``C.extends`` such that for each visible field in ``C``, any field that is equal to or overrides a field in ``t'`` should have the same value in ``t``. ``this`` should also map to the same value in ``t`` and ``t'``. @@ -2033,7 +2016,7 @@ The complete grammar for QL is as follows: import ::= annotations "import" importModuleId ("as" modulename)? - qualId ::= simpleId | qualId "." simpleId + qualId ::= simpleId | qualId "." simpleId importModuleId ::= qualId | importModuleId "::" simpleId @@ -2072,18 +2055,18 @@ The complete grammar for QL is as follows: head ::= ("predicate" | type) predicateName "(" var_decls ")" optbody ::= ";" - | "{" formula "}" + | "{" formula "}" | "=" literalId "(" (predicateRef "/" int ("," predicateRef "/" int)*)? ")" "(" (exprs)? ")" class ::= qldoc? annotations "class" classname "extends" type ("," type)* "{" member* "}" member ::= character | predicate | field - character ::= qldoc? annotations classname "(" ")" "{" formula "}" + character ::= qldoc? annotations classname "(" ")" "{" formula "}" field ::= qldoc? annotations var_decl ";" - moduleId ::= simpleId | moduleId "::" simpleId + moduleId ::= simpleId | moduleId "::" simpleId type ::= (moduleId "::")? classname | dbasetype | "boolean" | "date" | "float" | "int" | "string" @@ -2092,7 +2075,7 @@ The complete grammar for QL is as follows: alias ::= qldoc? annotations "predicate" literalId "=" predicateRef "/" int ";" | qldoc? annotations "class" classname "=" type ";" | qldoc? annotations "module" modulename "=" moduleId ";" - + var_decls ::= (var_decl ("," var_decl)*)? var_decl ::= type lowerId @@ -2108,7 +2091,7 @@ The complete grammar for QL is as follows: | instanceof | inrange | call - + fparen ::= "(" formula ")" disjunction ::= formula "or" formula @@ -2128,7 +2111,7 @@ The complete grammar for QL is as follows: comparison ::= expr compop expr - compop ::= "=" | "!=" | "<" | ">" | "<=" | ">=" + compop ::= "=" | "!=" | "<" | ">" | "<=" | ">=" instanceof ::= expr "instanceof" type @@ -2146,7 +2129,7 @@ The complete grammar for QL is as follows: | primary - primary ::= eparen + primary ::= eparen | literal | variable | super_expr @@ -2175,7 +2158,7 @@ The complete grammar for QL is as follows: variable ::= varname | "this" | "result" - super_expr ::= "super" | type "." "super" + super_expr ::= "super" | type "." "super" cast ::= "(" type ")" expr @@ -2184,7 +2167,7 @@ The complete grammar for QL is as follows: aggregation ::= aggid ("[" expr "]")? "(" var_decls ("|" (formula)? ("|" as_exprs ("order" "by" aggorderbys)?)?)? ")" | aggid ("[" expr "]")? "(" as_exprs ("order" "by" aggorderbys)? ")" | "unique" "(" var_decls "|" (formula)? ("|" as_exprs)? ")" - + expression_pragma ::= "pragma" "[" expression_pragma_type "]" "(" expr ")" expression_pragma_type ::= "only_bind_out" | "only_bind_into" @@ -2199,9 +2182,9 @@ The complete grammar for QL is as follows: callwithresults ::= predicateRef (closure)? "(" (exprs)? ")" | primary "." predicateName (closure)? "(" (exprs)? ")" - + range ::= "[" expr ".." expr "]" - + setliteral ::= "[" expr ("," expr)* ","? "]" simpleId ::= lowerId | upperId diff --git a/docs/codeql/ql-language-reference/signatures.rst b/docs/codeql/ql-language-reference/signatures.rst new file mode 100644 index 00000000000..f7f08eaf3d6 --- /dev/null +++ b/docs/codeql/ql-language-reference/signatures.rst @@ -0,0 +1,120 @@ +:tocdepth: 1 + +.. index:: signature + +.. _signatures: + +Signatures +########## + +Parameterized modules use signatures as a type system for their parameters. +There are three categories of signatures: **predicate signatures**, **type signatures**, and **module signatures**. + +Predicate signatures +==================== + +Predicate signatures declare module parameters that will be substituted with predicates when the module is instantiated. + +The substitution of predicate signatures relies on structural typing. That is, predicates do not have to be explicitly +defined as implementing a predicate signature - they just have to match the return and argument types. + +Predicate signatures are defined much like predicates themselves, but they do not have a body. +In detail, a predicate signature definition consists of: + +#. The keyword ``signature``. +#. The keyword ``predicate`` (allows subsitution with a :ref:`predicate without result `), + or the type of the result (allows subsitution with a :ref:`predicate with result `). +#. The name of the predicate signature. This is an `identifier `_ + starting with a lowercase letter. +#. The arguments to the predicate signature, if any, separated by commas. + For each argument, specify the argument type and an identifier for the argument variable. +#. A semicolon ``;``. + +For example: + +.. code-block:: ql + + signature int operator(int lhs, int rhs); + +Type signatures +=============== + +Type signatures declare module parameters that will be substituted with types when the module is instantiated. +Type signatures are used to specify supertypes and are the simplest category of signatures. + +The substitution of type signatures relies on structural typing. That is, types do not have to be explicitly defined as +implementing a type signature - they just need to have the specified (transitive) supertypes. + +In detail, a type signature definition consists of: + +#. The keyword ``signature``. +#. The keyword ``class``. +#. The name of the type signature. This is an `identifier `_ + starting with a uppercase letter. +#. Optionally, the keyword ``extends`` followed by a list of types, separated by commas. +#. A semicolon ``;``. + +For example: + +.. code-block:: ql + + signature class ExtendsInt extends int; + +Module signatures +================= + +Module signatures declare module parameters that will be substituted with modules when the module is instantiated. +Module signatures specify a collection of types and predicates that a module needs to contain under given names and +matching given signatures. + +Unlike type signatures and predicate signatures, the substitution of type signatures relies on nominal typing. +That is, the definition of a module must declare the module signatures it implements. + +In detail, a type signature definition consists of: + +#. The keyword ``signature``. +#. The keyword ``module``. +#. The name of the module signature. This is an `identifier `_ + starting with a uppercase letter. +#. Optionally, a list of parameters for :ref:`parameterized module signatures `. +#. The module signature body, consisting of type signatures and predicate signatures enclosed in braces. + The ``signature`` keyword is omitted for these contained signatures. + +For example: + +.. code-block:: ql + + signature module MSig { + class T; + predicate restriction(T t); + } + + module Module implements MSig { + newtype T = A() or B(); + + predicate restriction(T t) { t = A() } + } + +.. _parameterized-module-signatures: + +Parameterized module signatures +------------------------------- + +Module signatures can themselves be parameterized in exactly the same way as parameterized modules. +This is particularly useful in combination with the dependent typing of module parameters. + +For example: + +.. code-block:: ql + + signature class NodeSig; + + signature module EdgeSig { + predicate apply(Node src, Node dst); + } + + module Reachability Edge> { + Node reachableFrom(Node src) { + Edge::apply+(src, result) + } + } diff --git a/docs/codeql/reusables/download-github-database.rst b/docs/codeql/reusables/download-github-database.rst index 732d4479ba7..56e15078740 100644 --- a/docs/codeql/reusables/download-github-database.rst +++ b/docs/codeql/reusables/download-github-database.rst @@ -7,8 +7,8 @@ For example, to check for CodeQL databases using the `GitHub CLI //code-scanning/codeql/databases/ -H 'Accept: application/zip' > path/to/local/database.zip -For more information, see the documentation for the `Get CodeQL database `__ endpoint in the GitHub REST API documentation. \ No newline at end of file +For more information, see the documentation for the `Get CodeQL database `__ endpoint in the GitHub REST API documentation. diff --git a/docs/codeql/support/reusables/versions-compilers.rst b/docs/codeql/support/reusables/versions-compilers.rst index c734cf65ff3..21a0526af5f 100644 --- a/docs/codeql/support/reusables/versions-compilers.rst +++ b/docs/codeql/support/reusables/versions-compilers.rst @@ -23,7 +23,7 @@ JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_" Python,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10",Not applicable,``.py`` Ruby [7]_,"up to 3.0.2",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" - TypeScript [8]_,"2.6-4.7",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" + TypeScript [8]_,"2.6-4.8",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" .. container:: footnote-group diff --git a/docs/ql-design-patterns.md b/docs/ql-design-patterns.md index 6984088e925..b6d7eab88fc 100644 --- a/docs/ql-design-patterns.md +++ b/docs/ql-design-patterns.md @@ -31,13 +31,9 @@ Applying the `::Range` pattern yields the following: * Extend this class to refine existing API models. If you want to model new APIs, * extend `MySpecialExpr::Range` instead. */ -class MySpecialExpr extends Expr { - MySpecialExpr::Range range; - - MySpecialExpr() { this = range } - +class MySpecialExpr extends Expr instanceof MySpecialExpr::Range { /** */ - int memberPredicate() { result = range.memberPredicate() } + int memberPredicate() { result = super.memberPredicate() } } /** Provides a class for modeling new <...> APIs. */ @@ -56,22 +52,18 @@ module MySpecialExpr { ``` Now, a concrete subclass can derive from `MySpecialExpr::Range` if it wants to extend the set of values in `MySpecialExpr`, and it will be required to implement the abstract `memberPredicate()`. Conversely, if it wants to refine `MySpecialExpr` and override `memberPredicate` for all extensions, it can do so by deriving from `MySpecialExpr` directly. -The key element of the pattern is to provide a field of type `MySpecialExpr::Range`, equating it to `this` in the characteristic predicate of `MySpecialExpr`. In member predicates, we can use either `this` or `range`, depending on which type has the API we need. - -Note that in some libraries, the `range` field is in fact called `self`. While we do recommend using `range` for consistency, the name of the field does not matter (and using `range` avoids confusion in contexts like Python analysis that has strong usage of `self`). - ### Rationale -Let's use an example from the Go libraries: https://github.com/github/codeql-go/blob/2ba9bbfd8ba1818b5ee9f6009c86a605189c9ef3/ql/src/semmle/go/Concepts.qll#L119-L157 +Let's use an example from the Python libraries: https://github.com/github/codeql/blob/46751e515c40c6b4c9b61758cc840eec1894a624/python/ql/lib/semmle/python/Concepts.qll#L601-L683 -`EscapeFunction`, as the name suggests, models various APIs that escape meta-characters. It has a member-predicate `kind()` that tells you what sort of escaping the modelled function does. For example, if the result of that predicate is `"js"`, then this means that the escaping function is meant to make things safe to embed inside JavaScript. -`EscapeFunction::Range` is subclassed to model various APIs, and `kind()` is implemented accordingly. -But we can also subclass `EscapeFunction` to, as in the above example, talk about all JS-escaping functions. +`Escaping`, as the name suggests, models various APIs that escape meta-characters. It has a member-predicate `getKind()` that tells you what sort of escaping the modeled function does. For example, if the result of that predicate is `"html"`, then this means that the escaping function is meant to make things safe to embed inside HTML. +`Escaping::Range` is subclassed to model various APIs, and `kind()` is implemented accordingly (this typically happens in library models). +But we can also subclass `Escaping`, as in the above example, where `HtmlEscaping` represents all HTML-escaping functions. You can, of course, do the same without the `::Range` pattern, but it's a little cumbersome: -If you only had an `abstract class EscapeFunction { ... }`, then `JsEscapeFunction` would need to be implemented in a slightly tricky way to prevent it from extending `EscapeFunction` (instead of refining it). You would have to give it a charpred `this instanceof EscapeFunction`, which looks useless but isn't. And additionally, you'd have to provide trivial `none()` overrides of all the abstract predicates defined in `EscapeFunction`. This is all pretty awkward, and we can avoid it by distinguishing between `EscapeFunction` and `EscapeFunction::Range`. +If you only had an `abstract class Escaping { ... }`, then `HtmlEscaping` would need to be implemented in a slightly tricky way to prevent it from extending `Escaping` (instead of refining it). You would have to give it a charpred `this instanceof Escaping`, which looks useless but isn't. And additionally, you'd have to provide trivial `none()` overrides of all the abstract predicates defined in `Escaping`. This is all pretty awkward, and we can avoid it by distinguishing between `Escaping` and `Escaping::Range`. ## Importing all subclasses of a class diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 5660a08f72e..9b4b291a75a 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -179,7 +179,15 @@ The select clause of each alert query defines the alert message that is displaye * The message should factually describe the problem that is being highlighted–it should not contain recommendations about how to fix the problem or value judgements. * Program element references should be in 'single quotes' to distinguish them from ordinary words. Quotes are not needed around substitutions (`$@`). * Avoid constant alert message strings and include some context, if possible. For example, `The class 'Foo' is duplicated as 'Bar'.` is preferable to `This class is duplicated here.` +* If a reference to the current location can't be avoided use "this location" instead of "here". For example, `Bad thing at this location.` is preferable to `Bad thing here.`. This avoids the "click here" anti-pattern. +* For path queries, if possible, try to follow the template: `This path depends on a [user-provided value].`, or alternatively (if the first option doesn't work) `[User-provided value] flows to this location and is used in a path.`. +* Taint tracking queries generally have a sink that "depends on" the source, and dataflow queries generally have a source that "flows to" the sink. + +### Links in alert messages + * Where you reference another program element, link to it if possible using a substitution (`$@`). Links should be used inline in the sentence, rather than as parenthesised lists or appositions. +* Avoid using link texts that don't describe what they link to. For example, rewrite `This sensitive data is written to a logfile unescaped [here]` to `This sensitive data is [written to a logfile unescaped]`. +* Make link text as concise and precise as possible. For example, avoid starting a link text with an indefinite article (a, an). `Path construction depends on a [user-provided value]` is preferable to `Path construction depends on [a user-provided value]`. (Where the square brackets indicate a link.) See [the W3C guide on link texts](https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html) for further information. * When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining the results of a query](https://codeql.github.com/docs/writing-codeql-queries/defining-the-results-of-a-query/). For examples of select clauses and alert messages, see the query source files at the following pages: diff --git a/go/Makefile b/go/Makefile index b7da089c48a..419b1991775 100644 --- a/go/Makefile +++ b/go/Makefile @@ -14,7 +14,7 @@ CODEQL_PLATFORM = osx64 endif endif -CODEQL_TOOLS = $(addprefix codeql-tools/,autobuild.cmd autobuild.sh pre-finalize.cmd pre-finalize.sh index.cmd index.sh linux64 osx64 win64 tracing-config.lua) +CODEQL_TOOLS = $(addprefix codeql-tools/,autobuild.cmd autobuild.sh pre-finalize.cmd pre-finalize.sh index.cmd index.sh tracing-config.lua) EXTRACTOR_PACK_OUT = build/codeql-extractor-go diff --git a/go/codeql-tools/linux64/compiler-tracing.spec b/go/codeql-tools/linux64/compiler-tracing.spec deleted file mode 100644 index 2055555c21a..00000000000 --- a/go/codeql-tools/linux64/compiler-tracing.spec +++ /dev/null @@ -1,7 +0,0 @@ -**/go-autobuilder: - order compiler - trace no -**/go: - invoke ${config_dir}/go-extractor - prepend --mimic - prepend "${compiler}" diff --git a/go/codeql-tools/osx64/compiler-tracing.spec b/go/codeql-tools/osx64/compiler-tracing.spec deleted file mode 100644 index 2055555c21a..00000000000 --- a/go/codeql-tools/osx64/compiler-tracing.spec +++ /dev/null @@ -1,7 +0,0 @@ -**/go-autobuilder: - order compiler - trace no -**/go: - invoke ${config_dir}/go-extractor - prepend --mimic - prepend "${compiler}" diff --git a/go/codeql-tools/win64/compiler-tracing.spec b/go/codeql-tools/win64/compiler-tracing.spec deleted file mode 100644 index 76a6b011405..00000000000 --- a/go/codeql-tools/win64/compiler-tracing.spec +++ /dev/null @@ -1,7 +0,0 @@ -**/go-autobuilder.exe: - order compiler - trace no -**/go.exe: - invoke ${config_dir}/go-extractor.exe - prepend --mimic - prepend "${compiler}" diff --git a/go/ql/lib/change-notes/2022-09-12-uppercase.md b/go/ql/lib/change-notes/2022-09-12-uppercase.md new file mode 100644 index 00000000000..996861f1c2c --- /dev/null +++ b/go/ql/lib/change-notes/2022-09-12-uppercase.md @@ -0,0 +1,5 @@ +--- +category: deprecated +--- +* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. + The old name still exists as a deprecated alias. \ No newline at end of file diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll index f3920c2ec5c..c6043ae46b3 100644 --- a/go/ql/lib/semmle/go/Concepts.qll +++ b/go/ql/lib/semmle/go/Concepts.qll @@ -16,16 +16,12 @@ import semmle.go.concepts.GeneratedFile * Extend this class to refine existing API models. If you want to model new APIs, * extend `SystemCommandExecution::Range` instead. */ -class SystemCommandExecution extends DataFlow::Node { - SystemCommandExecution::Range self; - - SystemCommandExecution() { this = self } - +class SystemCommandExecution extends DataFlow::Node instanceof SystemCommandExecution::Range { /** Gets the argument that specifies the command to be executed. */ - DataFlow::Node getCommandName() { result = self.getCommandName() } + DataFlow::Node getCommandName() { result = super.getCommandName() } /** Holds if this node is sanitized whenever it follows `--` in an argument list. */ - predicate doubleDashIsSanitizing() { self.doubleDashIsSanitizing() } + predicate doubleDashIsSanitizing() { super.doubleDashIsSanitizing() } } /** Provides a class for modeling new system-command execution APIs. */ @@ -52,22 +48,18 @@ module SystemCommandExecution { * Extend this class to refine existing API models. If you want to model new APIs, * extend `TemplateInstantiation::Range` instead. */ -class TemplateInstantiation extends DataFlow::Node { - TemplateInstantiation::Range self; - - TemplateInstantiation() { this = self } - +class TemplateInstantiation extends DataFlow::Node instanceof TemplateInstantiation::Range { /** * Gets the argument to this template instantiation that is the template being * instantiated. */ - DataFlow::Node getTemplateArgument() { result = self.getTemplateArgument() } + DataFlow::Node getTemplateArgument() { result = super.getTemplateArgument() } /** * Gets an argument to this template instantiation that is data being inserted * into the template. */ - DataFlow::Node getADataArgument() { result = self.getADataArgument() } + DataFlow::Node getADataArgument() { result = super.getADataArgument() } } /** Provides a class for modeling new template-instantiation APIs. */ @@ -100,13 +92,9 @@ module TemplateInstantiation { * Extend this class to refine existing API models. If you want to model new APIs, * extend `FileSystemAccess::Range` instead. */ -class FileSystemAccess extends DataFlow::Node { - FileSystemAccess::Range self; - - FileSystemAccess() { this = self } - +class FileSystemAccess extends DataFlow::Node instanceof FileSystemAccess::Range { /** Gets an argument to this file system access that is interpreted as a path. */ - DataFlow::Node getAPathArgument() { result = self.getAPathArgument() } + DataFlow::Node getAPathArgument() { result = super.getAPathArgument() } } /** Provides a class for modeling new file-system access APIs. */ @@ -125,17 +113,13 @@ module FileSystemAccess { } /** A function that escapes meta-characters to prevent injection attacks. */ -class EscapeFunction extends Function { - EscapeFunction::Range self; - - EscapeFunction() { this = self } - +class EscapeFunction extends Function instanceof EscapeFunction::Range { /** * The context that this function escapes for. * * Currently, this can be "js", "html", or "url". */ - string kind() { result = self.kind() } + string kind() { result = super.kind() } } /** Provides a class for modeling new escape-function APIs. */ @@ -161,7 +145,7 @@ module EscapeFunction { * JavaScript string literal. */ class JsEscapeFunction extends EscapeFunction { - JsEscapeFunction() { self.kind() = "js" } + JsEscapeFunction() { super.kind() = "js" } } /** @@ -170,7 +154,7 @@ class JsEscapeFunction extends EscapeFunction { * `

    {}

    `. */ class HtmlEscapeFunction extends EscapeFunction { - HtmlEscapeFunction() { self.kind() = "html" } + HtmlEscapeFunction() { super.kind() = "html" } } /** @@ -178,7 +162,7 @@ class HtmlEscapeFunction extends EscapeFunction { * of a URL. */ class UrlEscapeFunction extends EscapeFunction { - UrlEscapeFunction() { self.kind() = "url" } + UrlEscapeFunction() { super.kind() = "url" } } /** @@ -187,27 +171,23 @@ class UrlEscapeFunction extends EscapeFunction { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RegexpPattern::Range` instead. */ -class RegexpPattern extends DataFlow::Node { - RegexpPattern::Range self; - - RegexpPattern() { this = self } - +class RegexpPattern extends DataFlow::Node instanceof RegexpPattern::Range { /** * Gets the node where this pattern is parsed as a part of a regular * expression. */ - DataFlow::Node getAParse() { result = self.getAParse() } + DataFlow::Node getAParse() { result = super.getAParse() } /** * Gets this regexp pattern as a string. */ - string getPattern() { result = self.getPattern() } + string getPattern() { result = super.getPattern() } /** * Gets a use of this pattern, either as itself in an argument to a function or as a compiled * regexp object. */ - DataFlow::Node getAUse() { result = self.getAUse() } + DataFlow::Node getAUse() { result = super.getAUse() } } /** Provides a class for modeling new regular-expression APIs. */ @@ -244,15 +224,11 @@ module RegexpPattern { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RegexpMatchFunction::Range` instead. */ -class RegexpMatchFunction extends Function { - RegexpMatchFunction::Range self; - - RegexpMatchFunction() { this = self } - +class RegexpMatchFunction extends Function instanceof RegexpMatchFunction::Range { /** * Gets the function input that is the regexp being matched. */ - FunctionInput getRegexpArg() { result = self.getRegexpArg() } + FunctionInput getRegexpArg() { result = super.getRegexpArg() } /** * Gets the regexp pattern that is used in the call to this function `call`. @@ -264,12 +240,12 @@ class RegexpMatchFunction extends Function { /** * Gets the function input that is the string being matched against. */ - FunctionInput getValue() { result = self.getValue() } + FunctionInput getValue() { result = super.getValue() } /** * Gets the function output that is the Boolean result of the match function. */ - FunctionOutput getResult() { result = self.getResult() } + FunctionOutput getResult() { result = super.getResult() } } /** Provides a class for modeling new regular-expression matcher APIs. */ @@ -304,15 +280,11 @@ module RegexpMatchFunction { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RegexpReplaceFunction::Range` instead. */ -class RegexpReplaceFunction extends Function { - RegexpReplaceFunction::Range self; - - RegexpReplaceFunction() { this = self } - +class RegexpReplaceFunction extends Function instanceof RegexpReplaceFunction::Range { /** * Gets the function input that is the regexp that matches text to replace. */ - FunctionInput getRegexpArg() { result = self.getRegexpArg() } + FunctionInput getRegexpArg() { result = super.getRegexpArg() } /** * Gets the regexp pattern that is used to match patterns to replace in the call to this function @@ -326,13 +298,13 @@ class RegexpReplaceFunction extends Function { * Gets the function input corresponding to the source value, that is, the value that is having * its contents replaced. */ - FunctionInput getSource() { result = self.getSource() } + FunctionInput getSource() { result = super.getSource() } /** * Gets the function output corresponding to the result, that is, the value after replacement has * occurred. */ - FunctionOutput getResult() { result = self.getResult() } + FunctionOutput getResult() { result = super.getResult() } } /** Provides a class for modeling new regular-expression replacer APIs. */ @@ -369,13 +341,9 @@ module RegexpReplaceFunction { * Extend this class to refine existing API models. If you want to model new APIs, * extend `LoggerCall::Range` instead. */ -class LoggerCall extends DataFlow::Node { - LoggerCall::Range self; - - LoggerCall() { this = self } - +class LoggerCall extends DataFlow::Node instanceof LoggerCall::Range { /** Gets a node that is a part of the logged message. */ - DataFlow::Node getAMessageComponent() { result = self.getAMessageComponent() } + DataFlow::Node getAMessageComponent() { result = super.getAMessageComponent() } } /** Provides a class for modeling new logging APIs. */ @@ -398,19 +366,15 @@ module LoggerCall { * Extend this class to refine existing API models. If you want to model new APIs, * extend `MarshalingFunction::Range` instead. */ -class MarshalingFunction extends Function { - MarshalingFunction::Range self; - - MarshalingFunction() { this = self } - +class MarshalingFunction extends Function instanceof MarshalingFunction::Range { /** Gets an input that is encoded by this function. */ - FunctionInput getAnInput() { result = self.getAnInput() } + FunctionInput getAnInput() { result = super.getAnInput() } /** Gets the output that contains the encoded data produced by this function. */ - FunctionOutput getOutput() { result = self.getOutput() } + FunctionOutput getOutput() { result = super.getOutput() } /** Gets an identifier for the format this function encodes into, such as "JSON". */ - string getFormat() { result = self.getFormat() } + string getFormat() { result = super.getFormat() } } /** Provides a class for modeling new marshaling APIs. */ @@ -439,19 +403,15 @@ module MarshalingFunction { * Extend this class to refine existing API models. If you want to model new APIs, * extend `UnmarshalingFunction::Range` instead. */ -class UnmarshalingFunction extends Function { - UnmarshalingFunction::Range self; - - UnmarshalingFunction() { this = self } - +class UnmarshalingFunction extends Function instanceof UnmarshalingFunction::Range { /** Gets an input that is decoded by this function. */ - FunctionInput getAnInput() { result = self.getAnInput() } + FunctionInput getAnInput() { result = super.getAnInput() } /** Gets the output that contains the decoded data produced by this function. */ - FunctionOutput getOutput() { result = self.getOutput() } + FunctionOutput getOutput() { result = super.getOutput() } /** Gets an identifier for the format this function decodes from, such as "JSON". */ - string getFormat() { result = self.getFormat() } + string getFormat() { result = super.getFormat() } } /** Provides a class for modeling new unmarshaling APIs. */ diff --git a/go/ql/lib/semmle/go/StringOps.qll b/go/ql/lib/semmle/go/StringOps.qll index 70f83328c05..d88aea71e23 100644 --- a/go/ql/lib/semmle/go/StringOps.qll +++ b/go/ql/lib/semmle/go/StringOps.qll @@ -12,20 +12,16 @@ module StringOps { * Extend this class to refine existing API models. If you want to model new APIs, * extend `StringOps::HasPrefix::Range` instead. */ - class HasPrefix extends DataFlow::Node { - HasPrefix::Range range; - - HasPrefix() { range = this } - + class HasPrefix extends DataFlow::Node instanceof HasPrefix::Range { /** * Gets the `A` in `strings.HasPrefix(A, B)`. */ - DataFlow::Node getBaseString() { result = range.getBaseString() } + DataFlow::Node getBaseString() { result = super.getBaseString() } /** * Gets the `B` in `strings.HasPrefix(A, B)`. */ - DataFlow::Node getSubstring() { result = range.getSubstring() } + DataFlow::Node getSubstring() { result = super.getSubstring() } /** * Gets the polarity of the check. @@ -33,7 +29,7 @@ module StringOps { * If the polarity is `false` the check returns `true` if the string does not start * with the given substring. */ - boolean getPolarity() { result = range.getPolarity() } + boolean getPolarity() { result = super.getPolarity() } } class StartsWith = HasPrefix; @@ -241,25 +237,21 @@ module StringOps { * Extend this class to refine existing API models. If you want to model new APIs, * extend `StringOps::Concatenation::Range` instead. */ - class Concatenation extends DataFlow::Node { - Concatenation::Range self; - - Concatenation() { this = self } - + class Concatenation extends DataFlow::Node instanceof Concatenation::Range { /** * Gets the `n`th operand of this string concatenation, if there is a data-flow node for it. */ - DataFlow::Node getOperand(int n) { result = self.getOperand(n) } + DataFlow::Node getOperand(int n) { result = super.getOperand(n) } /** * Gets the string value of the `n`th operand of this string concatenation, if it is a constant. */ - string getOperandStringValue(int n) { result = self.getOperandStringValue(n) } + string getOperandStringValue(int n) { result = super.getOperandStringValue(n) } /** * Gets the number of operands of this string concatenation. */ - int getNumOperand() { result = self.getNumOperand() } + int getNumOperand() { result = super.getNumOperand() } } /** Provides predicates and classes for working with string concatenations. */ diff --git a/go/ql/lib/semmle/go/Util.qll b/go/ql/lib/semmle/go/Util.qll index ff597cdcc28..8c089054d90 100644 --- a/go/ql/lib/semmle/go/Util.qll +++ b/go/ql/lib/semmle/go/Util.qll @@ -12,7 +12,10 @@ class Boolean extends boolean { /** * Gets a regexp pattern that matches common top-level domain names. */ -string commonTLD() { +string commonTld() { // according to ranking by http://google.com/search?q=site:.<> result = "(?:com|org|edu|gov|uk|net|io)(?![a-z0-9])" } + +/** DEPRECATED: Alias for commonTld */ +deprecated string commonTLD() { result = commonTld() } diff --git a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll index dec6872120c..d1067b60ad0 100644 --- a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll +++ b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll @@ -43,8 +43,4 @@ module GeneratedFile { * Extend this class to refine existing API models. If you want to model new APIs, * extend `GeneratedFile::Range` instead. */ -class GeneratedFile extends File { - GeneratedFile::Range self; - - GeneratedFile() { this = self } -} +class GeneratedFile extends File instanceof GeneratedFile::Range { } diff --git a/go/ql/lib/semmle/go/concepts/HTTP.qll b/go/ql/lib/semmle/go/concepts/HTTP.qll index 89a716d4f1a..770f577b1ff 100644 --- a/go/ql/lib/semmle/go/concepts/HTTP.qll +++ b/go/ql/lib/semmle/go/concepts/HTTP.qll @@ -5,7 +5,7 @@ import go /** Provides classes for modeling HTTP-related APIs. */ -module HTTP { +module Http { /** Provides a class for modeling new HTTP response-writer APIs. */ module ResponseWriter { /** @@ -31,11 +31,7 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::ResponseWriter::Range` instead. */ - class ResponseWriter extends Variable { - ResponseWriter::Range self; - - ResponseWriter() { this = self } - + class ResponseWriter extends Variable instanceof ResponseWriter::Range { /** Gets the body that is written in this HTTP response. */ ResponseBody getBody() { result.getResponseWriter() = this } @@ -47,8 +43,8 @@ module HTTP { /** Gets a data-flow node that is a use of this response writer. */ DataFlow::Node getANode() { - result = self.getANode() or - result.(DataFlow::PostUpdateNode).getPreUpdateNode() = self.getANode() + result = super.getANode() or + result.(DataFlow::PostUpdateNode).getPreUpdateNode() = super.getANode() } } @@ -100,19 +96,15 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::HeaderWrite::Range` instead. */ - class HeaderWrite extends DataFlow::ExprNode { - HeaderWrite::Range self; - - HeaderWrite() { this = self } - + class HeaderWrite extends DataFlow::ExprNode instanceof HeaderWrite::Range { /** Gets the (lower-case) name of a header set by this definition. */ - string getHeaderName() { result = self.getHeaderName() } + string getHeaderName() { result = super.getHeaderName() } /** Gets the value of the header set by this definition. */ - string getHeaderValue() { result = self.getHeaderValue() } + string getHeaderValue() { result = super.getHeaderValue() } /** Holds if this header write defines the header `header`. */ - predicate definesHeader(string header, string value) { self.definesHeader(header, value) } + predicate definesHeader(string header, string value) { super.definesHeader(header, value) } /** * Gets the node representing the name of the header defined by this write. @@ -121,13 +113,13 @@ module HTTP { * sets the `Content-Type` header) may not have such a node, so callers should use * `getHeaderName` in preference to this method). */ - DataFlow::Node getName() { result = self.getName() } + DataFlow::Node getName() { result = super.getName() } /** Gets the node representing the value of the header defined by this write. */ - DataFlow::Node getValue() { result = self.getValue() } + DataFlow::Node getValue() { result = super.getValue() } /** Gets the response writer associated with this header write, if any. */ - ResponseWriter getResponseWriter() { result = self.getResponseWriter() } + ResponseWriter getResponseWriter() { result = super.getResponseWriter() } } /** A data-flow node whose value is written to an HTTP header. */ @@ -171,11 +163,7 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::RequestBody::Range` instead. */ - class RequestBody extends DataFlow::Node { - RequestBody::Range self; - - RequestBody() { this = self } - } + class RequestBody extends DataFlow::Node instanceof RequestBody::Range { } /** Provides a class for modeling new HTTP response-body APIs. */ module ResponseBody { @@ -191,7 +179,7 @@ module HTTP { /** Gets a content-type associated with this body. */ string getAContentType() { - exists(HTTP::HeaderWrite hw | hw = this.getResponseWriter().getAHeaderWrite() | + exists(Http::HeaderWrite hw | hw = this.getResponseWriter().getAHeaderWrite() | hw.getHeaderName() = "content-type" and result = hw.getHeaderValue() ) @@ -201,7 +189,7 @@ module HTTP { /** Gets a dataflow node for a content-type associated with this body. */ DataFlow::Node getAContentTypeNode() { - exists(HTTP::HeaderWrite hw | hw = this.getResponseWriter().getAHeaderWrite() | + exists(Http::HeaderWrite hw | hw = this.getResponseWriter().getAHeaderWrite() | hw.getHeaderName() = "content-type" and result = hw.getValue() ) @@ -215,19 +203,15 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::ResponseBody::Range` instead. */ - class ResponseBody extends DataFlow::Node { - ResponseBody::Range self; - - ResponseBody() { this = self } - + class ResponseBody extends DataFlow::Node instanceof ResponseBody::Range { /** Gets the response writer associated with this header write, if any. */ - ResponseWriter getResponseWriter() { result = self.getResponseWriter() } + ResponseWriter getResponseWriter() { result = super.getResponseWriter() } /** Gets a content-type associated with this body. */ - string getAContentType() { result = self.getAContentType() } + string getAContentType() { result = super.getAContentType() } /** Gets a dataflow node for a content-type associated with this body. */ - DataFlow::Node getAContentTypeNode() { result = self.getAContentTypeNode() } + DataFlow::Node getAContentTypeNode() { result = super.getAContentTypeNode() } } /** Provides a class for modeling new HTTP template response-body APIs. */ @@ -250,13 +234,9 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::TemplateResponseBody::Range` instead. */ - class TemplateResponseBody extends ResponseBody { - override TemplateResponseBody::Range self; - - TemplateResponseBody() { this = self } - + class TemplateResponseBody extends ResponseBody instanceof TemplateResponseBody::Range { /** Gets the read of the variable inside the template where this value is read. */ - HtmlTemplate::TemplateRead getRead() { result = self.getRead() } + HtmlTemplate::TemplateRead getRead() { result = super.getRead() } } /** Provides a class for modeling new HTTP client request APIs. */ @@ -285,15 +265,11 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::ClientRequest::Range` instead. */ - class ClientRequest extends DataFlow::Node { - ClientRequest::Range self; - - ClientRequest() { this = self } - + class ClientRequest extends DataFlow::Node instanceof ClientRequest::Range { /** * Gets the URL of the request. */ - DataFlow::Node getUrl() { result = self.getUrl() } + DataFlow::Node getUrl() { result = super.getUrl() } } /** Provides a class for modeling new HTTP redirect APIs. */ @@ -337,16 +313,12 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::Redirect::Range` instead. */ - class Redirect extends DataFlow::Node { - Redirect::Range self; - - Redirect() { this = self } - + class Redirect extends DataFlow::Node instanceof Redirect::Range { /** Gets the data-flow node representing the URL being redirected to. */ - DataFlow::Node getUrl() { result = self.getUrl() } + DataFlow::Node getUrl() { result = super.getUrl() } /** Gets the response writer that this redirect is sent on, if any. */ - ResponseWriter getResponseWriter() { result = self.getResponseWriter() } + ResponseWriter getResponseWriter() { result = super.getResponseWriter() } } /** Provides a class for modeling new HTTP handler APIs. */ @@ -369,12 +341,11 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::RequestHandler::Range` instead. */ - class RequestHandler extends DataFlow::Node { - RequestHandler::Range self; - - RequestHandler() { this = self } - + class RequestHandler extends DataFlow::Node instanceof RequestHandler::Range { /** Gets a node that is used in a check that is tested before this handler is run. */ - predicate guardedBy(DataFlow::Node check) { self.guardedBy(check) } + predicate guardedBy(DataFlow::Node check) { super.guardedBy(check) } } } + +/** DEPRECATED: Alias for Http */ +deprecated module HTTP = Http; diff --git a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll index c9c0c58b33e..511bbd4ddce 100644 --- a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll +++ b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll @@ -114,7 +114,7 @@ private predicate entryNode(ControlFlow::Node node) { node.isEntryNode() } * graph so that we can use the dominator tree to find the most recent * side-effect. */ -private predicate sideEffectCFG(ControlFlow::Node src, ControlFlow::Node dst) { +private predicate sideEffectCfg(ControlFlow::Node src, ControlFlow::Node dst) { src.getASuccessor() = dst or // Add an edge from the entry point to any node that might have a side @@ -128,7 +128,7 @@ private predicate sideEffectCFG(ControlFlow::Node src, ControlFlow::Node dst) { * the side-effect CFG. */ private predicate iDomEffect(ControlFlow::Node dominator, ControlFlow::Node node) = - idominance(entryNode/1, sideEffectCFG/2)(_, dominator, node) + idominance(entryNode/1, sideEffectCfg/2)(_, dominator, node) /** * Gets the most recent side effect. To be more precise, `result` is a @@ -190,7 +190,7 @@ private ControlFlow::Node mostRecentSideEffect(ControlFlow::Node node) { /** Used to represent the "global value number" of an expression. */ cached -private newtype GVNBase = +private newtype GvnBase = MkNumericConst(string val) { mkNumericConst(_, val) } or MkStringConst(string val) { mkStringConst(_, val) } or MkBoolConst(boolean val) { mkBoolConst(_, val) } or @@ -204,7 +204,7 @@ private newtype GVNBase = MkOtherVariable(ValueEntity x, ControlFlow::Node dominator) { mkOtherVariable(_, x, dominator) } or MkMethodAccess(GVN base, Function m) { mkMethodAccess(_, base, m) } or MkFieldRead(GVN base, Field f, ControlFlow::Node dominator) { mkFieldRead(_, base, f, dominator) } or - MkPureCall(Function f, GVN callee, GVNList args) { mkPureCall(_, f, callee, args) } or + MkPureCall(Function f, GVN callee, GvnList args) { mkPureCall(_, f, callee, args) } or MkIndex(GVN base, GVN index, ControlFlow::Node dominator) { mkIndex(_, base, index, dominator) } or // Dereference a pointer. The value might have changed since the last // time the pointer was dereferenced, so we need to include a definition @@ -217,22 +217,22 @@ private newtype GVNBase = // given a unique number based on the expression itself. MkUnanalyzable(DataFlow::Node e) { not analyzableExpr(e) } -private newtype GVNList = +private newtype GvnList = MkNil() or - MkCons(GVN head, GVNList tail) { globalValueNumbers(_, _, head, tail) } + MkCons(GVN head, GvnList tail) { globalValueNumbers(_, _, head, tail) } -private GVNList globalValueNumbers(DataFlow::CallNode ce, int start) { +private GvnList globalValueNumbers(DataFlow::CallNode ce, int start) { analyzableCall(ce, _) and start = ce.getNumArgument() and result = MkNil() or - exists(GVN head, GVNList tail | + exists(GVN head, GvnList tail | globalValueNumbers(ce, start, head, tail) and result = MkCons(head, tail) ) } -private predicate globalValueNumbers(DataFlow::CallNode ce, int start, GVN head, GVNList tail) { +private predicate globalValueNumbers(DataFlow::CallNode ce, int start, GVN head, GvnList tail) { analyzableCall(ce, _) and head = globalValueNumber(ce.getArgument(start)) and tail = globalValueNumbers(ce, start + 1) @@ -254,8 +254,8 @@ private predicate globalValueNumbers(DataFlow::CallNode ce, int start, GVN head, * expression with this `GVN` and using its `toString` and `getLocation` * methods. */ -class GVN extends GVNBase { - GVN() { this instanceof GVNBase } +class GVN extends GvnBase { + GVN() { this instanceof GvnBase } /** Gets a data-flow node that has this GVN. */ DataFlow::Node getANode() { this = globalValueNumber(result) } @@ -386,7 +386,7 @@ private predicate analyzableCall(DataFlow::CallNode ce, Function f) { not ce.isConst() } -private predicate mkPureCall(DataFlow::CallNode ce, Function f, GVN callee, GVNList args) { +private predicate mkPureCall(DataFlow::CallNode ce, Function f, GVN callee, GvnList args) { analyzableCall(ce, f) and callee = globalValueNumber(ce.getCalleeNode()) and args = globalValueNumbers(ce, 0) @@ -523,7 +523,7 @@ GVN globalValueNumber(DataFlow::Node nd) { result = MkFieldRead(qualifier, target, dominator) ) or - exists(Function f, GVN callee, GVNList args | + exists(Function f, GVN callee, GvnList args | mkPureCall(nd, f, callee, args) and result = MkPureCall(f, callee, args) ) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 7f4d87adbb5..ea3f757b440 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -341,13 +341,9 @@ module Public { } /** A function, viewed as a node in a data flow graph. */ - class FunctionNode extends Node { - FunctionNode::Range self; - - FunctionNode() { this = self } - + class FunctionNode extends Node instanceof FunctionNode::Range { /** Gets the `i`th parameter of this function. */ - ParameterNode getParameter(int i) { result = self.getParameter(i) } + ParameterNode getParameter(int i) { result = super.getParameter(i) } /** Gets a parameter of this function. */ ParameterNode getAParameter() { result = this.getParameter(_) } @@ -356,18 +352,18 @@ module Public { int getNumParameter() { result = count(this.getAParameter()) } /** Gets the name of this function, if it has one. */ - string getName() { result = self.getName() } + string getName() { result = super.getName() } /** * Gets the dataflow node holding the value of the receiver, if any. */ - ReceiverNode getReceiver() { result = self.getReceiver() } + ReceiverNode getReceiver() { result = super.getReceiver() } /** * Gets a value returned by the given function via a return statement or an assignment to a * result variable. */ - ResultNode getAResult() { result = self.getAResult() } + ResultNode getAResult() { result = super.getAResult() } /** * Gets the data-flow node corresponding to the `i`th result of this function. @@ -379,7 +375,7 @@ module Public { * * Note that this predicate has no result for function literals. */ - Function getFunction() { result = self.getFunction() } + Function getFunction() { result = super.getFunction() } } /** A representation of a function that is declared in the module scope. */ diff --git a/go/ql/lib/semmle/go/frameworks/Beego.qll b/go/ql/lib/semmle/go/frameworks/Beego.qll index edcf383c6be..6d927112584 100644 --- a/go/ql/lib/semmle/go/frameworks/Beego.qll +++ b/go/ql/lib/semmle/go/frameworks/Beego.qll @@ -114,7 +114,7 @@ module Beego { } } - private class BeegoOutputInstance extends HTTP::ResponseWriter::Range { + private class BeegoOutputInstance extends Http::ResponseWriter::Range { SsaWithFields v; BeegoOutputInstance() { @@ -131,7 +131,7 @@ module Beego { } } - private class BeegoHeaderWrite extends HTTP::HeaderWrite::Range, DataFlow::MethodCallNode { + private class BeegoHeaderWrite extends Http::HeaderWrite::Range, DataFlow::MethodCallNode { string methodName; BeegoHeaderWrite() { @@ -142,7 +142,7 @@ module Beego { override DataFlow::Node getName() { methodName = "Header" and result = this.getArgument(0) } override string getHeaderName() { - result = HTTP::HeaderWrite::Range.super.getHeaderName() + result = Http::HeaderWrite::Range.super.getHeaderName() or methodName = "ContentType" and result = "content-type" } @@ -153,12 +153,12 @@ module Beego { else result = this.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { + override Http::ResponseWriter getResponseWriter() { result.(BeegoOutputInstance).getAHeaderObject() = this } } - private class BeegoResponseBody extends HTTP::ResponseBody::Range { + private class BeegoResponseBody extends Http::ResponseBody::Range { DataFlow::MethodCallNode call; string methodName; @@ -170,7 +170,7 @@ module Beego { methodName in ["Body", "JSON", "JSONP", "ServeFormatted", "XML", "YAML"] } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = call.getReceiver() } + override Http::ResponseWriter getResponseWriter() { result.getANode() = call.getReceiver() } override string getAContentType() { // Super-method provides content-types for `Body`, which requires us to search @@ -192,7 +192,7 @@ module Beego { } } - private class ControllerResponseBody extends HTTP::ResponseBody::Range { + private class ControllerResponseBody extends Http::ResponseBody::Range { string name; ControllerResponseBody() { @@ -203,7 +203,7 @@ module Beego { ) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } override string getAContentType() { // Actually SetData can serve JSON, XML or YAML depending on the incoming @@ -213,7 +213,7 @@ module Beego { } } - private class ContextResponseBody extends HTTP::ResponseBody::Range { + private class ContextResponseBody extends Http::ResponseBody::Range { string name; ContextResponseBody() { @@ -224,7 +224,7 @@ module Beego { ) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } // Neither method is likely to be used with well-typed data such as JSON output, // because there are better methods to do this. Assume the Content-Type could @@ -314,7 +314,7 @@ module Beego { } } - private class RedirectMethods extends HTTP::Redirect::Range, DataFlow::CallNode { + private class RedirectMethods extends Http::Redirect::Range, DataFlow::CallNode { string package; string className; @@ -333,7 +333,7 @@ module Beego { className = "Context" and result = this.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } private class UtilsTaintPropagators extends TaintTracking::FunctionModel { diff --git a/go/ql/lib/semmle/go/frameworks/Echo.qll b/go/ql/lib/semmle/go/frameworks/Echo.qll index df58b492b87..c4d243b504c 100644 --- a/go/ql/lib/semmle/go/frameworks/Echo.qll +++ b/go/ql/lib/semmle/go/frameworks/Echo.qll @@ -29,7 +29,7 @@ private module Echo { /** * Data from a `Context` interface method that is not generally exploitable for open-redirect attacks. */ - private class EchoContextRedirectUnexploitableSource extends HTTP::Redirect::UnexploitableSource { + private class EchoContextRedirectUnexploitableSource extends Http::Redirect::UnexploitableSource { EchoContextRedirectUnexploitableSource() { exists(DataFlow::MethodCallNode call, string methodName | methodName = ["FormValue", "FormParams", "FormFile", "MultipartForm", "Cookie", "Cookies"] and @@ -77,14 +77,14 @@ private module Echo { /** * `echo.Context` methods which set the content-type to `text/html` and write a result in one operation. */ - private class EchoHtmlOutputs extends HTTP::ResponseBody::Range { + private class EchoHtmlOutputs extends Http::ResponseBody::Range { EchoHtmlOutputs() { exists(Method m | m.hasQualifiedName(packagePath(), "Context", ["HTML", "HTMLBlob"]) | this = m.getACall().getArgument(1) ) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } override string getAContentType() { result = "text/html" } } @@ -92,7 +92,7 @@ private module Echo { /** * `echo.Context` methods which take a content-type as a parameter. */ - private class EchoParameterizedOutputs extends HTTP::ResponseBody::Range { + private class EchoParameterizedOutputs extends Http::ResponseBody::Range { DataFlow::CallNode callNode; EchoParameterizedOutputs() { @@ -101,7 +101,7 @@ private module Echo { ) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } override DataFlow::Node getAContentTypeNode() { result = callNode.getArgument(1) } } @@ -109,7 +109,7 @@ private module Echo { /** * The `echo.Context.Redirect` method. */ - private class EchoRedirectMethod extends HTTP::Redirect::Range, DataFlow::CallNode { + private class EchoRedirectMethod extends Http::Redirect::Range, DataFlow::CallNode { EchoRedirectMethod() { exists(Method m | m.hasQualifiedName(packagePath(), "Context", "Redirect") | this = m.getACall() @@ -118,6 +118,6 @@ private module Echo { override DataFlow::Node getUrl() { result = this.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } } diff --git a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll index 87c091fc3c5..42fb474a5f0 100644 --- a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll +++ b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll @@ -11,7 +11,7 @@ module ElazarlGoproxy { /** Gets the package name. */ string packagePath() { result = package("github.com/elazarl/goproxy", "") } - private class NewResponse extends HTTP::HeaderWrite::Range, DataFlow::CallNode { + private class NewResponse extends Http::HeaderWrite::Range, DataFlow::CallNode { NewResponse() { this.getTarget().hasQualifiedName(packagePath(), "NewResponse") } override string getHeaderName() { this.definesHeader(result, _) } @@ -28,21 +28,21 @@ module ElazarlGoproxy { header = "content-type" and value = this.getArgument(1).getStringValue() } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } /** A body argument to a `NewResponse` call. */ - private class NewResponseBody extends HTTP::ResponseBody::Range { + private class NewResponseBody extends Http::ResponseBody::Range { NewResponse call; NewResponseBody() { this = call.getArgument(3) } override DataFlow::Node getAContentTypeNode() { result = call.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } - private class TextResponse extends HTTP::HeaderWrite::Range, DataFlow::CallNode { + private class TextResponse extends Http::HeaderWrite::Range, DataFlow::CallNode { TextResponse() { this.getTarget().hasQualifiedName(packagePath(), "TextResponse") } override string getHeaderName() { this.definesHeader(result, _) } @@ -59,22 +59,22 @@ module ElazarlGoproxy { header = "content-type" and value = "text/plain" } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } /** A body argument to a `TextResponse` call. */ - private class TextResponseBody extends HTTP::ResponseBody::Range, TextResponse { + private class TextResponseBody extends Http::ResponseBody::Range, TextResponse { TextResponse call; TextResponseBody() { this = call.getArgument(2) } override DataFlow::Node getAContentTypeNode() { result = call.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } /** A handler attached to a goproxy proxy type. */ - private class ProxyHandler extends HTTP::RequestHandler::Range { + private class ProxyHandler extends Http::RequestHandler::Range { DataFlow::MethodCallNode handlerReg; ProxyHandler() { diff --git a/go/ql/lib/semmle/go/frameworks/Email.qll b/go/ql/lib/semmle/go/frameworks/Email.qll index 049af5f87bf..340cdad3d10 100644 --- a/go/ql/lib/semmle/go/frameworks/Email.qll +++ b/go/ql/lib/semmle/go/frameworks/Email.qll @@ -9,11 +9,7 @@ import go * Extend this class to refine existing API models. If you want to model new APIs, * extend `EmailData::Range` instead. */ -class EmailData extends DataFlow::Node { - EmailData::Range self; - - EmailData() { this = self } -} +class EmailData extends DataFlow::Node instanceof EmailData::Range { } /** Provides classes for working with data that is incorporated into an email. */ module EmailData { diff --git a/go/ql/lib/semmle/go/frameworks/Macaron.qll b/go/ql/lib/semmle/go/frameworks/Macaron.qll index a38b2b20da0..f107ec208ee 100644 --- a/go/ql/lib/semmle/go/frameworks/Macaron.qll +++ b/go/ql/lib/semmle/go/frameworks/Macaron.qll @@ -5,7 +5,7 @@ import go private module Macaron { - private class Context extends HTTP::ResponseWriter::Range { + private class Context extends Http::ResponseWriter::Range { SsaWithFields v; Context() { @@ -18,13 +18,13 @@ private module Macaron { override DataFlow::Node getANode() { result = v.similar().getAUse().getASuccessor*() } } - private class RedirectCall extends HTTP::Redirect::Range, DataFlow::MethodCallNode { + private class RedirectCall extends Http::Redirect::Range, DataFlow::MethodCallNode { RedirectCall() { this.getTarget().hasQualifiedName("gopkg.in/macaron.v1", "Context", "Redirect") } override DataFlow::Node getUrl() { result = this.getArgument(0) } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getReceiver() } + override Http::ResponseWriter getResponseWriter() { result.getANode() = this.getReceiver() } } } diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll index 578cf67d33f..ff8190d854d 100644 --- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll +++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll @@ -12,11 +12,7 @@ module NoSql { * Extend this class to refine existing API models. If you want to model new APIs, * extend `NoSQL::Query::Range` instead. */ - class Query extends DataFlow::Node { - Query::Range self; - - Query() { this = self } - } + class Query extends DataFlow::Node instanceof Query::Range { } /** Provides classes for working with NoSql queries. */ module Query { diff --git a/go/ql/lib/semmle/go/frameworks/Revel.qll b/go/ql/lib/semmle/go/frameworks/Revel.qll index 1ccad431b84..d006f46b2ee 100644 --- a/go/ql/lib/semmle/go/frameworks/Revel.qll +++ b/go/ql/lib/semmle/go/frameworks/Revel.qll @@ -114,7 +114,7 @@ module Revel { * We look particularly for html file extensions, since these are the only ones we currently have special rules * for (in particular, detecting XSS vulnerabilities). */ - private class ControllerRenderMethods extends HTTP::ResponseBody::Range { + private class ControllerRenderMethods extends Http::ResponseBody::Range { string contentType; ControllerRenderMethods() { @@ -149,7 +149,7 @@ module Revel { ) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } override string getAContentType() { result = contentType } } @@ -174,7 +174,7 @@ module Revel { * It is currently assumed that a tainted `value` in `Redirect(url, value)`, which calls `Sprintf(url, value)` * internally, cannot lead to an open redirect vulnerability. */ - private class ControllerRedirectMethod extends HTTP::Redirect::Range, DataFlow::CallNode { + private class ControllerRedirectMethod extends Http::Redirect::Range, DataFlow::CallNode { ControllerRedirectMethod() { exists(Method m | m.hasQualifiedName(packagePath(), "Controller", "Redirect") | this = m.getACall() @@ -183,7 +183,7 @@ module Revel { override DataFlow::Node getUrl() { result = this.getArgument(0) } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } } /** @@ -226,7 +226,7 @@ module Revel { /** * A write to a template argument field that is read raw inside of a template. */ - private class RawTemplateArgument extends HTTP::TemplateResponseBody::Range { + private class RawTemplateArgument extends Http::TemplateResponseBody::Range { RawTemplateRead read; RawTemplateArgument() { @@ -261,7 +261,7 @@ module Revel { override string getAContentType() { result = "text/html" } - override HTTP::ResponseWriter getResponseWriter() { none() } + override Http::ResponseWriter getResponseWriter() { none() } override HtmlTemplate::TemplateRead getRead() { result = read } } diff --git a/go/ql/lib/semmle/go/frameworks/SQL.qll b/go/ql/lib/semmle/go/frameworks/SQL.qll index 66566f7540c..322d17a420a 100644 --- a/go/ql/lib/semmle/go/frameworks/SQL.qll +++ b/go/ql/lib/semmle/go/frameworks/SQL.qll @@ -12,13 +12,9 @@ module SQL { * Extend this class to refine existing API models. If you want to model new APIs, * extend `SQL::Query::Range` instead. */ - class Query extends DataFlow::Node { - Query::Range self; - - Query() { this = self } - + class Query extends DataFlow::Node instanceof Query::Range { /** Gets a result of this query execution. */ - DataFlow::Node getAResult() { result = self.getAResult() } + DataFlow::Node getAResult() { result = super.getAResult() } /** * Gets a query string that is used as (part of) this SQL query. @@ -26,7 +22,7 @@ module SQL { * Note that this may not resolve all `QueryString`s that should be associated with this * query due to data flow. */ - QueryString getAQueryString() { result = self.getAQueryString() } + QueryString getAQueryString() { result = super.getAQueryString() } } /** @@ -59,11 +55,7 @@ module SQL { * Extend this class to refine existing API models. If you want to model new APIs, * extend `SQL::QueryString::Range` instead. */ - class QueryString extends DataFlow::Node { - QueryString::Range self; - - QueryString() { this = self } - } + class QueryString extends DataFlow::Node instanceof QueryString::Range { } /** Provides classes for working with SQL query strings. */ module QueryString { diff --git a/go/ql/lib/semmle/go/frameworks/Stdlib.qll b/go/ql/lib/semmle/go/frameworks/Stdlib.qll index b8481175216..db46167d205 100644 --- a/go/ql/lib/semmle/go/frameworks/Stdlib.qll +++ b/go/ql/lib/semmle/go/frameworks/Stdlib.qll @@ -128,7 +128,7 @@ module IntegerParser { } /** Provides models of commonly used functions in the `net/url` package. */ -module URL { +module Url { /** The `PathEscape` or `QueryEscape` function. */ class Escaper extends TaintTracking::FunctionModel { Escaper() { @@ -263,3 +263,6 @@ module URL { } } } + +/** DEPRECATED: Alias for Url */ +deprecated module URL = Url; diff --git a/go/ql/lib/semmle/go/frameworks/Testing.qll b/go/ql/lib/semmle/go/frameworks/Testing.qll index 2df3d6c0ddd..f56e58288e5 100644 --- a/go/ql/lib/semmle/go/frameworks/Testing.qll +++ b/go/ql/lib/semmle/go/frameworks/Testing.qll @@ -8,11 +8,7 @@ import go * Extend this class to refine existing models of testing frameworks. If you want to model new * frameworks, extend `TestCase::Range` instead. */ -class TestCase extends AstNode { - TestCase::Range self; - - TestCase() { this = self } -} +class TestCase extends AstNode instanceof TestCase::Range { } /** Provides classes for working with test cases. */ module TestCase { @@ -47,11 +43,7 @@ module TestCase { * Extend this class to refine existing models of testing frameworks. If you want to model new * frameworks, extend `TestFile::Range` instead. */ -class TestFile extends File { - TestFile::Range self; - - TestFile() { this = self } -} +class TestFile extends File instanceof TestFile::Range { } /** Provides classes for working with test files. */ module TestFile { diff --git a/go/ql/lib/semmle/go/frameworks/WebSocket.qll b/go/ql/lib/semmle/go/frameworks/WebSocket.qll index d3264467b45..44445b538b2 100644 --- a/go/ql/lib/semmle/go/frameworks/WebSocket.qll +++ b/go/ql/lib/semmle/go/frameworks/WebSocket.qll @@ -8,13 +8,9 @@ import go * Extend this class to refine existing API models. If you want to model new APIs, * extend `WebSocketRequestCall::Range` instead. */ -class WebSocketRequestCall extends DataFlow::CallNode { - WebSocketRequestCall::Range self; - - WebSocketRequestCall() { this = self } - +class WebSocketRequestCall extends DataFlow::CallNode instanceof WebSocketRequestCall::Range { /** Gets the URL of the request. */ - DataFlow::Node getRequestUrl() { result = self.getRequestUrl() } + DataFlow::Node getRequestUrl() { result = super.getRequestUrl() } } /** Provides classes for working with WebSocket request functions. */ @@ -143,13 +139,9 @@ class WebSocketReaderAsSource extends UntrustedFlowSource::Range { * Extend this class to refine existing API models. If you want to model new APIs, * extend `WebSocketReader::Range` instead. */ -class WebSocketReader extends Function { - WebSocketReader::Range self; - - WebSocketReader() { this = self } - +class WebSocketReader extends Function instanceof WebSocketReader::Range { /** Gets an output of this function containing data that is read from a WebSocket connection. */ - FunctionOutput getAnOutput() { result = self.getAnOutput() } + FunctionOutput getAnOutput() { result = super.getAnOutput() } } /** Provides classes for working with messages read from a WebSocket. */ diff --git a/go/ql/lib/semmle/go/frameworks/XPath.qll b/go/ql/lib/semmle/go/frameworks/XPath.qll index 896007f4641..e3b7282c4e3 100644 --- a/go/ql/lib/semmle/go/frameworks/XPath.qll +++ b/go/ql/lib/semmle/go/frameworks/XPath.qll @@ -12,11 +12,7 @@ module XPath { * Extend this class to refine existing API models. If you want to model new APIs, * extend `XPath::XPathExpressionString::Range` instead. */ - class XPathExpressionString extends DataFlow::Node { - XPathExpressionString::Range self; - - XPathExpressionString() { this = self } - } + class XPathExpressionString extends DataFlow::Node instanceof XPathExpressionString::Range { } /** Provides classes for working with XPath expression strings. */ module XPathExpressionString { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll index c5e48e7d295..e0518ecf465 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll @@ -35,7 +35,7 @@ module NetHttp { } /** The declaration of a variable which either is or has a field that implements the http.ResponseWriter type */ - private class StdlibResponseWriter extends HTTP::ResponseWriter::Range { + private class StdlibResponseWriter extends Http::ResponseWriter::Range { SsaWithFields v; StdlibResponseWriter() { @@ -52,7 +52,7 @@ module NetHttp { } } - private class HeaderWriteCall extends HTTP::HeaderWrite::Range, DataFlow::MethodCallNode { + private class HeaderWriteCall extends Http::HeaderWrite::Range, DataFlow::MethodCallNode { HeaderWriteCall() { this.getTarget().hasQualifiedName("net/http", "Header", "Add") or this.getTarget().hasQualifiedName("net/http", "Header", "Set") @@ -62,7 +62,7 @@ module NetHttp { override DataFlow::Node getValue() { result = this.getArgument(1) } - override HTTP::ResponseWriter getResponseWriter() { + override Http::ResponseWriter getResponseWriter() { // find `v` in // ``` // header := v.Header() @@ -72,7 +72,7 @@ module NetHttp { } } - private class MapWrite extends HTTP::HeaderWrite::Range, DataFlow::Node { + private class MapWrite extends Http::HeaderWrite::Range, DataFlow::Node { Write write; DataFlow::Node index; DataFlow::Node rhs; @@ -86,7 +86,7 @@ module NetHttp { override DataFlow::Node getValue() { result = rhs } - override HTTP::ResponseWriter getResponseWriter() { + override Http::ResponseWriter getResponseWriter() { // find `v` in // ``` // header := v.Header() @@ -96,7 +96,7 @@ module NetHttp { } } - private class ResponseWriteHeaderCall extends HTTP::HeaderWrite::Range, DataFlow::MethodCallNode { + private class ResponseWriteHeaderCall extends Http::HeaderWrite::Range, DataFlow::MethodCallNode { ResponseWriteHeaderCall() { this.getTarget().implements("net/http", "ResponseWriter", "WriteHeader") } @@ -107,10 +107,10 @@ module NetHttp { override DataFlow::Node getValue() { result = this.getArgument(0) } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getReceiver() } + override Http::ResponseWriter getResponseWriter() { result.getANode() = this.getReceiver() } } - private class ResponseErrorCall extends HTTP::HeaderWrite::Range, DataFlow::CallNode { + private class ResponseErrorCall extends Http::HeaderWrite::Range, DataFlow::CallNode { ResponseErrorCall() { this.getTarget().hasQualifiedName("net/http", "Error") } override string getHeaderName() { result = "status" } @@ -119,10 +119,10 @@ module NetHttp { override DataFlow::Node getValue() { result = this.getArgument(2) } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(0) } + override Http::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(0) } } - private class RequestBody extends HTTP::RequestBody::Range, DataFlow::ExprNode { + private class RequestBody extends Http::RequestBody::Range, DataFlow::ExprNode { RequestBody() { exists(Function newRequest | newRequest.hasQualifiedName("net/http", "NewRequest") and @@ -137,7 +137,7 @@ module NetHttp { } } - private class ResponseBody extends HTTP::ResponseBody::Range, DataFlow::ArgumentNode { + private class ResponseBody extends Http::ResponseBody::Range, DataFlow::ArgumentNode { DataFlow::Node responseWriter; ResponseBody() { @@ -156,19 +156,19 @@ module NetHttp { ) } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = responseWriter } + override Http::ResponseWriter getResponseWriter() { result.getANode() = responseWriter } } - private class RedirectCall extends HTTP::Redirect::Range, DataFlow::CallNode { + private class RedirectCall extends Http::Redirect::Range, DataFlow::CallNode { RedirectCall() { this.getTarget().hasQualifiedName("net/http", "Redirect") } override DataFlow::Node getUrl() { result = this.getArgument(2) } - override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(0) } + override Http::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(0) } } /** A call to a function in the `net/http` package that performs an HTTP request to a URL. */ - private class RequestCall extends HTTP::ClientRequest::Range, DataFlow::CallNode { + private class RequestCall extends Http::ClientRequest::Range, DataFlow::CallNode { RequestCall() { exists(string functionName | ( @@ -185,7 +185,7 @@ module NetHttp { } /** A call to the Client.Do function in the `net/http` package. */ - private class ClientDo extends HTTP::ClientRequest::Range, DataFlow::MethodCallNode { + private class ClientDo extends Http::ClientRequest::Range, DataFlow::MethodCallNode { ClientDo() { this.getTarget().hasQualifiedName("net/http", "Client", "Do") } override DataFlow::Node getUrl() { @@ -212,7 +212,7 @@ module NetHttp { } /** A call to the `Transport.RoundTrip` function in the `net/http` package. */ - private class TransportRoundTrip extends HTTP::ClientRequest::Range, DataFlow::MethodCallNode { + private class TransportRoundTrip extends Http::ClientRequest::Range, DataFlow::MethodCallNode { TransportRoundTrip() { this.getTarget().hasQualifiedName("net/http", "Transport", "RoundTrip") } override DataFlow::Node getUrl() { @@ -239,7 +239,7 @@ module NetHttp { } /** Fields and methods of `net/http.Request` that are not generally exploitable in an open-redirect attack. */ - private class RedirectUnexploitableRequestFields extends HTTP::Redirect::UnexploitableSource { + private class RedirectUnexploitableRequestFields extends Http::Redirect::UnexploitableSource { RedirectUnexploitableRequestFields() { exists(Field f, string fieldName | f.hasQualifiedName("net/http", "Request", fieldName) and @@ -257,7 +257,7 @@ module NetHttp { } } - private class Handler extends HTTP::RequestHandler::Range { + private class Handler extends Http::RequestHandler::Range { DataFlow::CallNode handlerReg; Handler() { diff --git a/go/ql/lib/semmle/go/security/FlowSources.qll b/go/ql/lib/semmle/go/security/FlowSources.qll index c1e08710e06..de8fb5c3732 100644 --- a/go/ql/lib/semmle/go/security/FlowSources.qll +++ b/go/ql/lib/semmle/go/security/FlowSources.qll @@ -11,11 +11,7 @@ private import semmle.go.dataflow.ExternalFlow as ExternalFlow * Extend this class to refine existing API models. If you want to model new APIs, * extend `UntrustedFlowSource::Range` instead. */ -class UntrustedFlowSource extends DataFlow::Node { - UntrustedFlowSource::Range self; - - UntrustedFlowSource() { this = self } -} +class UntrustedFlowSource extends DataFlow::Node instanceof UntrustedFlowSource::Range { } /** Provides a class for modeling new sources of untrusted data. */ module UntrustedFlowSource { diff --git a/go/ql/lib/semmle/go/security/InsecureRandomness.qll b/go/ql/lib/semmle/go/security/InsecureRandomness.qll index f2db5860073..6de3071b598 100644 --- a/go/ql/lib/semmle/go/security/InsecureRandomness.qll +++ b/go/ql/lib/semmle/go/security/InsecureRandomness.qll @@ -29,5 +29,7 @@ module InsecureRandomness { /** Holds if `sink` is a sink for this configuration with kind `kind`. */ predicate isSink(Sink sink, string kind) { kind = sink.getKind() } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } } diff --git a/go/ql/lib/semmle/go/security/OpenUrlRedirectCustomizations.qll b/go/ql/lib/semmle/go/security/OpenUrlRedirectCustomizations.qll index d883c3c0101..80b9bb4a126 100644 --- a/go/ql/lib/semmle/go/security/OpenUrlRedirectCustomizations.qll +++ b/go/ql/lib/semmle/go/security/OpenUrlRedirectCustomizations.qll @@ -56,7 +56,7 @@ module OpenUrlRedirect { UntrustedFlowAsSource() { // exclude some fields and methods of URLs that are generally not attacker-controllable for // open redirect exploits - not this instanceof HTTP::Redirect::UnexploitableSource + not this instanceof Http::Redirect::UnexploitableSource } } @@ -64,7 +64,7 @@ module OpenUrlRedirect { * An HTTP redirect, considered as a sink for `Configuration`. */ class RedirectSink extends Sink, DataFlow::Node { - RedirectSink() { this = any(HTTP::Redirect redir).getUrl() } + RedirectSink() { this = any(Http::Redirect redir).getUrl() } } /** @@ -73,7 +73,7 @@ module OpenUrlRedirect { */ class LocationHeaderSink extends Sink, DataFlow::Node { LocationHeaderSink() { - exists(HTTP::HeaderWrite hw | hw.getHeaderName() = "location" | this = hw.getValue()) + exists(Http::HeaderWrite hw | hw.getHeaderName() = "location" | this = hw.getValue()) } } diff --git a/go/ql/lib/semmle/go/security/RequestForgeryCustomizations.qll b/go/ql/lib/semmle/go/security/RequestForgeryCustomizations.qll index b75b3503d55..b11157daa06 100644 --- a/go/ql/lib/semmle/go/security/RequestForgeryCustomizations.qll +++ b/go/ql/lib/semmle/go/security/RequestForgeryCustomizations.qll @@ -48,7 +48,7 @@ module RequestForgery { * The URL of an HTTP request, viewed as a sink for request forgery. */ private class ClientRequestUrlAsSink extends Sink { - HTTP::ClientRequest request; + Http::ClientRequest request; ClientRequestUrlAsSink() { this = request.getUrl() } diff --git a/go/ql/lib/semmle/go/security/SafeUrlFlowCustomizations.qll b/go/ql/lib/semmle/go/security/SafeUrlFlowCustomizations.qll index de0f95f8f3a..dbdb96a10a7 100644 --- a/go/ql/lib/semmle/go/security/SafeUrlFlowCustomizations.qll +++ b/go/ql/lib/semmle/go/security/SafeUrlFlowCustomizations.qll @@ -27,7 +27,7 @@ module SafeUrlFlow { /** * A method on a `net/url.URL` that is considered unsafe to use. */ - private class UnsafeUrlMethod extends URL::UrlGetter { + private class UnsafeUrlMethod extends Url::UrlGetter { UnsafeUrlMethod() { this.getName() = "Query" } } diff --git a/go/ql/lib/semmle/go/security/Xss.qll b/go/ql/lib/semmle/go/security/Xss.qll index 2ed5c5761a7..98b6da02fe8 100644 --- a/go/ql/lib/semmle/go/security/Xss.qll +++ b/go/ql/lib/semmle/go/security/Xss.qll @@ -6,8 +6,11 @@ import go /** Provides classes and predicates shared between the XSS queries. */ module SharedXss { - /** A data flow source for XSS vulnerabilities. */ - abstract class Source extends DataFlow::Node { } + /** + * DEPRECATED: This class is not used. + * A data flow source for XSS vulnerabilities. + */ + abstract deprecated class Source extends DataFlow::Node { } /** A data flow sink for XSS vulnerabilities. */ abstract class Sink extends DataFlow::Node { @@ -46,14 +49,14 @@ module SharedXss { * a content type that does not (case-insensitively) contain the string "html". This * is to prevent us from flagging plain-text or JSON responses as vulnerable. */ - class HttpResponseBodySink extends Sink, HTTP::ResponseBody { + class HttpResponseBodySink extends Sink, Http::ResponseBody { HttpResponseBodySink() { not nonHtmlContentType(this) } } /** * An expression that is rendered as part of a template. */ - class RawTemplateInstantiationSink extends HttpResponseBodySink, HTTP::TemplateResponseBody { + class RawTemplateInstantiationSink extends HttpResponseBodySink, Http::TemplateResponseBody { override string getSinkKind() { result = "rawtemplate" } override Locatable getAssociatedLoc() { result = this.getRead().getEnclosingTextNode() } @@ -62,7 +65,7 @@ module SharedXss { /** * Holds if `body` may send a response with a content type other than HTML. */ - private predicate nonHtmlContentType(HTTP::ResponseBody body) { + private predicate nonHtmlContentType(Http::ResponseBody body) { not htmlTypeSpecified(body) and ( exists(body.getAContentType()) @@ -90,7 +93,7 @@ module SharedXss { /** * Holds if `body` specifies the response's content type to be HTML. */ - private predicate htmlTypeSpecified(HTTP::ResponseBody body) { + private predicate htmlTypeSpecified(Http::ResponseBody body) { body.getAContentType().regexpMatch("(?i).*html.*") } diff --git a/go/ql/src/RedundantCode/DuplicateCondition.ql b/go/ql/src/RedundantCode/DuplicateCondition.ql index ac3c586eda4..3d7416450dc 100644 --- a/go/ql/src/RedundantCode/DuplicateCondition.ql +++ b/go/ql/src/RedundantCode/DuplicateCondition.ql @@ -24,10 +24,10 @@ Expr getCondition(IfStmt stmt, int i) { } /** Gets the global value number of `e`, which is the `i`th condition of `is`. */ -GVN conditionGVN(IfStmt is, int i, Expr e) { +GVN conditionGvn(IfStmt is, int i, Expr e) { e = getCondition(is, i) and result = e.getGlobalValueNumber() } from IfStmt is, Expr e, Expr f, int i, int j -where conditionGVN(is, i, e) = conditionGVN(is, j, f) and i < j +where conditionGvn(is, i, e) = conditionGvn(is, j, f) and i < j select f, "This condition is a duplicate of $@.", e, "an earlier condition" diff --git a/go/ql/src/RedundantCode/DuplicateSwitchCase.ql b/go/ql/src/RedundantCode/DuplicateSwitchCase.ql index 7af97b76875..b2777a1131f 100644 --- a/go/ql/src/RedundantCode/DuplicateSwitchCase.ql +++ b/go/ql/src/RedundantCode/DuplicateSwitchCase.ql @@ -14,10 +14,10 @@ import go /** Gets the global value number of `e`, which is the `i`th case label of `switch`. */ -GVN switchCaseGVN(SwitchStmt switch, int i, Expr e) { +GVN switchCaseGvn(SwitchStmt switch, int i, Expr e) { e = switch.getCase(i).getExpr(0) and result = e.getGlobalValueNumber() } from SwitchStmt switch, int i, Expr e, int j, Expr f -where switchCaseGVN(switch, i, e) = switchCaseGVN(switch, j, f) and i < j +where switchCaseGvn(switch, i, e) = switchCaseGvn(switch, j, f) and i < j select f, "This case is a duplicate of $@.", e, "an earlier case" diff --git a/go/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql b/go/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql index ef0ec60d871..4272d1cc27e 100644 --- a/go/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql +++ b/go/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql @@ -28,12 +28,12 @@ predicate isIncompleteHostNameRegexpPattern(string pattern, string hostPart) { "(?`_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,,, - `Apache Commons IO `_,``org.apache.commons.io``,,561,104,89,,,,,,15 + `Apache Commons IO `_,``org.apache.commons.io``,,556,106,91,,,,,,15 `Apache Commons Lang `_,``org.apache.commons.lang3``,,424,,,,,,,, `Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,, `Apache HttpComponents `_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25 `Google Guava `_,``com.google.common.*``,,728,39,,6,,,,, `JSON-java `_,``org.json``,,236,,,,,,,, - Java Standard Library,``java.*``,3,577,130,28,,,7,,,10 + Java Standard Library,``java.*``,3,585,130,28,,,7,,,10 Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2 - `Spring `_,``org.springframework.*``,29,476,101,,,,19,14,,29 - Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin.jvm.internal``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,395,932,,,,14,18,,3 - Totals,,217,6438,1474,117,6,10,107,33,1,84 + `Spring `_,``org.springframework.*``,29,477,101,,,,19,14,,29 + Others,"``androidx.core.app``, ``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,2324,950,10,,,14,18,,5 + Totals,,217,8426,1502,129,6,10,107,33,1,86 diff --git a/java/kotlin-extractor/build.py b/java/kotlin-extractor/build.py index 3f14eb0b28e..a4da1a2ea23 100755 --- a/java/kotlin-extractor/build.py +++ b/java/kotlin-extractor/build.py @@ -86,7 +86,8 @@ def compile_to_dir(srcs, classpath, java_classpath, output): run_process([kotlinc, # kotlinc can default to 256M, which isn't enough when we are extracting the build '-J-Xmx2G', - '-Xopt-in=kotlin.RequiresOptIn', + '-Werror', + '-opt-in=kotlin.RequiresOptIn', '-d', output, '-module-name', 'codeql-kotlin-extractor', '-no-reflect', '-no-stdlib', diff --git a/java/kotlin-extractor/generate_dbscheme.py b/java/kotlin-extractor/generate_dbscheme.py index 9e517505469..fb891fb105c 100755 --- a/java/kotlin-extractor/generate_dbscheme.py +++ b/java/kotlin-extractor/generate_dbscheme.py @@ -171,13 +171,12 @@ with open('src/main/kotlin/KotlinExtractorDbScheme.kt', 'w') as kt: for num, typ in mapping: genTable(kt, relname, columns, enum, kind, num, typ) + kt.write('sealed interface AnyDbType\n') for typ in sorted(supertypes): - kt.write('sealed interface Db' + upperFirst(typ)) + kt.write('sealed interface Db' + upperFirst(typ) + ': AnyDbType') # Sorting makes the output deterministic. names = sorted(supertypes[typ]) - if names: - kt.write(': ') - kt.write(', '.join(map(lambda name: 'Db' + upperFirst(name), names))) + kt.write(''.join(map(lambda name: ', Db' + upperFirst(name), names))) kt.write('\n') for alias in sorted(type_aliases): kt.write('typealias Db' + upperFirst(alias) + ' = Db' + upperFirst(type_aliases[alias]) + '\n') diff --git a/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java b/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java index 73dc090f69b..22fcbdf0011 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java @@ -255,17 +255,6 @@ public class OdasaOutput { * Trap writers. */ - /** - * A {@link TrapFileManager} to output facts for the given source file, - * or null if the source file should not be populated. - */ - private TrapFileManager getTrapWriterForCurrentSourceFile() { - File trapFile = getTrapFileForCurrentSourceFile(); - if (trapFile==null) - return null; - return trapWriter(trapFile, null, null); - } - /** * Get a {@link TrapFileManager} to write members * about a declaration, or null if the declaration shouldn't be populated. diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt index d6f25d73efa..3b58400eca5 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt @@ -354,7 +354,12 @@ private fun getTrapFileWriter(compression: Compression, logger: FileLogger, trap return when (compression) { Compression.NONE -> NonCompressedTrapFileWriter(logger, trapFileName) Compression.GZIP -> GZipCompressedTrapFileWriter(logger, trapFileName) - Compression.BROTLI -> throw Exception("Brotli compression is not supported by the Kotlin extractor") + Compression.BROTLI -> { + // Brotli should have been replaced with gzip earlier, but + // if we somehow manage to get here then keep going + logger.error("Impossible Brotli compression requested. Using Gzip instead.") + getTrapFileWriter(Compression.GZIP, logger, trapFileName) + } } } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 30a5f7380bd..45636455806 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -83,8 +83,12 @@ open class KotlinFileExtractor( } file.declarations.forEach { extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true) } - extractStaticInitializer(file, null) + extractStaticInitializer(file, { extractFileClass(file) }) CommentExtractor(this, file, tw.fileId).extract() + + if (!declarationStack.isEmpty()) { + logger.errorElement("Declaration stack is not empty after processing the file", file) + } } } @@ -159,31 +163,6 @@ open class KotlinFileExtractor( } } - - - fun getLabel(element: IrElement) : String? { - when (element) { - is IrClass -> return getClassLabel(element, listOf()).classLabel - is IrTypeParameter -> return getTypeParameterLabel(element) - is IrFunction -> return getFunctionLabel(element, null) - is IrValueParameter -> return getValueParameterLabel(element, null) - is IrProperty -> return getPropertyLabel(element) - is IrField -> return getFieldLabel(element) - is IrEnumEntry -> return getEnumEntryLabel(element) - is IrTypeAlias -> return getTypeAliasLabel(element) - - // Fresh entities: - is IrBody -> return null - is IrExpression -> return null - - // todo add others: - else -> { - logger.errorElement("Unhandled element type: ${element::class}", element) - return null - } - } - } - private fun extractTypeParameter(tp: IrTypeParameter, apparentIndex: Int, javaTypeParameter: JavaTypeParameter?): Label? { with("type parameter", tp) { val parentId = getTypeParameterParentLabel(tp) ?: return null @@ -331,7 +310,7 @@ open class KotlinFileExtractor( } }.firstOrNull { it != null } ?: false) - extractEnclosingClass(c, id, locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf()) + extractEnclosingClass(c.parent, id, c, locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf()) return id } @@ -414,11 +393,7 @@ open class KotlinFileExtractor( with("class source", c) { DeclarationStackAdjuster(c).use { - val id = if (c.isAnonymousObject) { - useAnonymousClass(c).javaResult.id.cast() - } else { - useClassSource(c) - } + val id = useClassSource(c) val pkg = c.packageFqName?.asString() ?: "" val cls = if (c.isAnonymousObject) "" else c.name.asString() val pkgId = extractPackage(pkg) @@ -444,7 +419,7 @@ open class KotlinFileExtractor( val locId = tw.getLocation(c) tw.writeHasLocation(id, locId) - extractEnclosingClass(c, id, locId, listOf()) + extractEnclosingClass(c.parent, id, c, locId, listOf()) val javaClass = (c.source as? JavaSourceElement)?.javaElement as? JavaClass @@ -452,7 +427,7 @@ open class KotlinFileExtractor( if (extractDeclarations) { c.declarations.forEach { extractDeclaration(it, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) } if (extractStaticInitializer) - extractStaticInitializer(c, id) + extractStaticInitializer(c, { id }) extractJvmStaticProxyMethods(c, id, extractPrivateMembers, extractFunctionBodies) } if (c.isNonCompanionObject) { @@ -551,10 +526,21 @@ open class KotlinFileExtractor( } } - // If `parentClassTypeArguments` is null, the parent class is a raw type. - private fun extractEnclosingClass(innerDeclaration: IrDeclaration, innerId: Label, innerLocId: Label, parentClassTypeArguments: List?) { - with("enclosing class", innerDeclaration) { - var parent: IrDeclarationParent? = innerDeclaration.parent + /** + * This function traverses the declaration-parent hierarchy upwards, and retrieves the enclosing class of a class to extract the `enclInReftype` relation. + * Additionally, it extracts a companion field for a companion object into its parent class. + * + * Note that the nested class can also be a local class declared inside a function, so the upwards traversal is skipping the non-class parents. Also, in some cases the file class is the enclosing one, which has no IR representation. + */ + private fun extractEnclosingClass( + declarationParent: IrDeclarationParent, // The declaration parent of the element for which we are extracting the enclosing class + innerId: Label, // ID of the inner class + innerClass: IrClass?, // The inner class, if available. It's not available if the enclosing class of a generated class is being extracted + innerLocId: Label, // Location of the inner class + parentClassTypeArguments: List? // Type arguments of the parent class. If `parentClassTypeArguments` is null, the parent class is a raw type + ) { + with("enclosing class", declarationParent) { + var parent: IrDeclarationParent? = declarationParent while (parent != null) { if (parent is IrClass) { val parentId = @@ -564,13 +550,13 @@ open class KotlinFileExtractor( useClassInstance(parent, parentClassTypeArguments).typeResult.id } tw.writeEnclInReftype(innerId, parentId) - if (innerDeclaration is IrClass && innerDeclaration.isCompanion) { + if (innerClass != null && innerClass.isCompanion) { // If we are a companion then our parent has a // public static final ParentClass$CompanionObjectClass CompanionObjectName; // that we need to fabricate here - val instance = useCompanionObjectClassInstance(innerDeclaration) + val instance = useCompanionObjectClassInstance(innerClass) if (instance != null) { - val type = useSimpleTypeClass(innerDeclaration, emptyList(), false) + val type = useSimpleTypeClass(innerClass, emptyList(), false) tw.writeFields(instance.id, instance.name, type.javaResult.id, parentId, instance.id) tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, innerLocId) @@ -581,7 +567,7 @@ open class KotlinFileExtractor( break } else if (parent is IrFile) { - if (innerDeclaration is IrClass) { + if (innerClass != null) { // We don't have to extract file class containers for classes break } @@ -667,13 +653,18 @@ open class KotlinFileExtractor( return type } - private fun extractStaticInitializer(container: IrDeclarationContainer, classLabel: Label?) { + /** + * mkContainerLabel is a lambda so that we get laziness: If the + * container is a file, then we don't want to extract the file class + * unless something actually needs it. + */ + private fun extractStaticInitializer(container: IrDeclarationContainer, mkContainerLabel: () -> Label) { with("static initializer extraction", container) { extractDeclInitializers(container.declarations, true) { - val parentId = classLabel ?: extractFileClass(container as IrFile) + val containerId = mkContainerLabel() val clinitLabel = getFunctionLabel( container, - parentId, + containerId, "", listOf(), pluginContext.irBuiltIns.unitType, @@ -686,7 +677,7 @@ open class KotlinFileExtractor( ) val clinitId = tw.getLabelFor(clinitLabel) val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN) - tw.writeMethods(clinitId, "", "()", returnType.javaResult.id, parentId, clinitId) + tw.writeMethods(clinitId, "", "()", returnType.javaResult.id, containerId, clinitId) tw.writeMethodsKotlinType(clinitId, returnType.kotlinResult.id) tw.writeCompiler_generated(clinitId, CompilerGeneratedKinds.CLASS_INITIALISATION_METHOD.kind) @@ -934,7 +925,6 @@ open class KotlinFileExtractor( private fun extractField(f: IrField, parentId: Label): Label { with("field", f) { DeclarationStackAdjuster(f).use { - declarationStack.push(f) val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(".", "$$") } ?: "" return extractField(useField(f), "${f.name.asString()}$fNameSuffix", f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal) } @@ -1343,6 +1333,14 @@ open class KotlinFileExtractor( val receiverClass = receiverType.classifier.owner as? IrClass ?: return listOf() val ancestorTypes = ArrayList() + // KFunctionX doesn't implement FunctionX on versions before 1.7.0: + if ((callTarget.name.asString() == "invoke") && + (receiverClass.fqNameWhenAvailable?.asString()?.startsWith("kotlin.reflect.KFunction") == true) && + (callTarget.parentClassOrNull?.fqNameWhenAvailable?.asString()?.startsWith("kotlin.Function") == true) + ) { + return receiverType.arguments + } + // Populate ancestorTypes with the path from receiverType's class to its ancestor, callTarget's declaring type. fun walkFrom(c: IrClass): Boolean { if(declaringType == c) @@ -1361,16 +1359,25 @@ open class KotlinFileExtractor( } // If a path was found, repeatedly substitute types to get the corresponding specialisation of that ancestor. - return if (!walkFrom(receiverClass)) { + if (!walkFrom(receiverClass)) { logger.errorElement("Failed to find a class declaring ${callTarget.name} starting at ${receiverClass.name}", callTarget) - listOf() + return listOf() } else { - var subbedType = receiverType + var subbedType: IrSimpleType = receiverType ancestorTypes.forEach { - val thisClass = subbedType.classifier.owner as IrClass - subbedType = it.substituteTypeArguments(thisClass.typeParameters, subbedType.arguments) as IrSimpleType + val thisClass = subbedType.classifier.owner + if (thisClass !is IrClass) { + logger.errorElement("Found ancestor with unexpected type ${thisClass.javaClass}", callTarget) + return listOf() + } + val itSubbed = it.substituteTypeArguments(thisClass.typeParameters, subbedType.arguments) + if (itSubbed !is IrSimpleType) { + logger.errorElement("Substituted type has unexpected type ${itSubbed.javaClass}", callTarget) + return listOf() + } + subbedType = itSubbed } - subbedType.arguments + return subbedType.arguments } } @@ -1452,12 +1459,14 @@ open class KotlinFileExtractor( // type arguments at index -2, -3, ... extractTypeArguments(typeArguments, locId, id, enclosingCallable, enclosingStmt, -2, true) - val isFunctionInvoke = drType != null - && drType is IrSimpleType - && drType.isFunctionOrKFunction() - && callTarget.name.asString() == OperatorNameConventions.INVOKE.asString() - val isBigArityFunctionInvoke = isFunctionInvoke - && (drType as IrSimpleType).arguments.size > BuiltInFunctionArity.BIG_ARITY + val (isFunctionInvoke, isBigArityFunctionInvoke) = + if (drType is IrSimpleType && + drType.isFunctionOrKFunction() && + callTarget.name.asString() == OperatorNameConventions.INVOKE.asString()) { + Pair(true, drType.arguments.size > BuiltInFunctionArity.BIG_ARITY) + } else { + Pair(false, false) + } if (callTarget.isLocalFunction()) { val ids = getLocallyVisibleFunctionLabels(callTarget) @@ -1468,7 +1477,7 @@ open class KotlinFileExtractor( extractNewExprForLocalFunction(ids, id, locId, enclosingCallable, enclosingStmt) } else { val methodId = - if (drType != null && extractClassTypeArguments && drType is IrSimpleType && !isUnspecialised(drType)) { + if (extractClassTypeArguments && drType is IrSimpleType && !isUnspecialised(drType, logger)) { val extractionMethod = if (isFunctionInvoke) { // For `kotlin.FunctionX` and `kotlin.reflect.KFunctionX` interfaces, we're making sure that we @@ -1544,19 +1553,18 @@ open class KotlinFileExtractor( } private fun extractStaticTypeAccessQualifier(target: IrDeclaration, parentExpr: Label, locId: Label, enclosingCallable: Label, enclosingStmt: Label) { - if (target.shouldExtractAsStaticMemberOfClass) { - extractTypeAccessRecursive(target.parentAsClass.toRawType(), locId, parentExpr, -1, enclosingCallable, enclosingStmt) - } else if (target.shouldExtractAsStaticMemberOfFile) { - extractTypeAccess(useFileClassType(target.parent as IrFile), locId, parentExpr, -1, enclosingCallable, enclosingStmt) + if (target.shouldExtractAsStatic) { + val parent = target.parent + if (parent is IrClass) { + extractTypeAccessRecursive(parent.toRawType(), locId, parentExpr, -1, enclosingCallable, enclosingStmt) + } else if (parent is IrFile) { + extractTypeAccess(useFileClassType(parent), locId, parentExpr, -1, enclosingCallable, enclosingStmt) + } else { + logger.warnElement("Unexpected static type access qualifer ${parent.javaClass}", target) + } } } - private val IrDeclaration.shouldExtractAsStaticMemberOfClass: Boolean - get() = this.shouldExtractAsStatic && parent is IrClass - - private val IrDeclaration.shouldExtractAsStaticMemberOfFile: Boolean - get() = this.shouldExtractAsStatic && parent is IrFile - private fun isStaticAnnotatedNonCompanionMember(f: IrSimpleFunction) = f.parentClassOrNull?.isNonCompanionObject == true && (f.hasAnnotation(jvmStaticFqName) || f.correspondingPropertySymbol?.owner?.hasAnnotation(jvmStaticFqName) == true) @@ -1584,7 +1592,7 @@ open class KotlinFileExtractor( } } - private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction? + private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.findSubType { it.name.asString() == name } val jvmIntrinsicsClass by lazy { val result = pluginContext.referenceClass(FqName("kotlin.jvm.internal.Intrinsics"))?.owner @@ -1600,11 +1608,13 @@ open class KotlinFileExtractor( return result } - private fun findTopLevelFunctionOrWarn(functionFilter: String, type: String, warnAgainstElement: IrElement): IrFunction? { + private fun findTopLevelFunctionOrWarn(functionFilter: String, type: String, parameterTypes: Array, warnAgainstElement: IrElement): IrFunction? { val fn = pluginContext.referenceFunctions(FqName(functionFilter)) - .firstOrNull { it.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type } - ?.owner + .firstOrNull { fnSymbol -> + fnSymbol.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type && + fnSymbol.owner.valueParameters.map { it.type.classFqName?.asString() }.toTypedArray() contentEquals parameterTypes + }?.owner if (fn != null) { if (fn.parentClassOrNull != null) { @@ -1641,12 +1651,11 @@ open class KotlinFileExtractor( } val stringValueOfObjectMethod by lazy { - val result = javaLangString?.declarations?.find { - it is IrFunction && + val result = javaLangString?.declarations?.findSubType { it.name.asString() == "valueOf" && it.valueParameters.size == 1 && it.valueParameters[0].type == pluginContext.irBuiltIns.anyNType - } as IrFunction? + } if (result == null) { logger.error("Couldn't find declaration java.lang.String.valueOf(Object)") } @@ -1654,9 +1663,9 @@ open class KotlinFileExtractor( } val objectCloneMethod by lazy { - val result = javaLangObject?.declarations?.find { - it is IrFunction && it.name.asString() == "clone" - } as IrFunction? + val result = javaLangObject?.declarations?.findSubType { + it.name.asString() == "clone" + } if (result == null) { logger.error("Couldn't find declaration java.lang.Object.clone(...)") } @@ -1670,10 +1679,9 @@ open class KotlinFileExtractor( } val kotlinNoWhenBranchMatchedConstructor by lazy { - val result = kotlinNoWhenBranchMatchedExn?.declarations?.find { - it is IrConstructor && + val result = kotlinNoWhenBranchMatchedExn?.declarations?.findSubType { it.valueParameters.isEmpty() - } as IrConstructor? + } if (result == null) { logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException") } @@ -1686,7 +1694,7 @@ open class KotlinFileExtractor( result } - private fun isFunction(target: IrFunction, pkgName: String, classNameLogged: String, classNamePredicate: (String) -> Boolean, fName: String, hasQuestionMark: Boolean? = false): Boolean { + private fun isFunction(target: IrFunction, pkgName: String, classNameLogged: String, classNamePredicate: (String) -> Boolean, fName: String, isNullable: Boolean? = false): Boolean { val verbose = false fun verboseln(s: String) { if(verbose) println(s) } verboseln("Attempting match for $pkgName $classNameLogged $fName") @@ -1696,14 +1704,14 @@ open class KotlinFileExtractor( } val extensionReceiverParameter = target.extensionReceiverParameter val targetClass = if (extensionReceiverParameter == null) { - if (hasQuestionMark == true) { + if (isNullable == true) { verboseln("Nullablility of type didn't match (target is not an extension method)") return false } target.parent } else { val st = extensionReceiverParameter.type as? IrSimpleType - if (hasQuestionMark != null && st?.hasQuestionMark != hasQuestionMark) { + if (isNullable != null && st?.isNullable() != isNullable) { verboseln("Nullablility of type didn't match") return false } @@ -1730,8 +1738,8 @@ open class KotlinFileExtractor( return true } - private fun isFunction(target: IrFunction, pkgName: String, className: String, fName: String, hasQuestionMark: Boolean? = false) = - isFunction(target, pkgName, className, { it == className }, fName, hasQuestionMark) + private fun isFunction(target: IrFunction, pkgName: String, className: String, fName: String, isNullable: Boolean? = false) = + isFunction(target, pkgName, className, { it == className }, fName, isNullable) private fun isNumericFunction(target: IrFunction, fName: String): Boolean { return isFunction(target, "kotlin", "Int", fName) || @@ -1756,6 +1764,12 @@ open class KotlinFileExtractor( else -> false } + private fun isGenericArrayType(typeName: String) = + when(typeName) { + "Array" -> true + else -> false + } + private fun extractCall(c: IrCall, callable: Label, stmtExprParent: StmtExprParent) { with("call", c) { val target = tryReplaceSyntheticFunction(c.symbol.owner) @@ -1798,13 +1812,35 @@ open class KotlinFileExtractor( return } - val func = ((c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner as? IrClass)?.declarations?.find { it is IrFunction && it.name.asString() == fnName } - if (func == null) { - logger.errorElement("Couldn't find function $fnName on enum type", c) + val enumType = (c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner + if (enumType == null) { + logger.errorElement("Couldn't find type of enum type", c) return } - extractMethodAccess(func as IrFunction, false) + if (enumType is IrClass) { + val func = enumType.declarations.findSubType { it.name.asString() == fnName } + if (func == null) { + logger.errorElement("Couldn't find function $fnName on enum type", c) + return + } + + extractMethodAccess(func, false) + } else if (enumType is IrTypeParameter && enumType.isReified) { + // A call to `enumValues()` is being extracted, where `T` is a reified type parameter of an `inline` function. + // We can't generate a valid expression here, because we would need to know the type of T on the call site. + // TODO: replace error expression with something that better shows this expression is unrepresentable. + val id = tw.getFreshIdLabel() + val type = useType(c.type) + + tw.writeExprs_errorexpr(id, type.javaResult.id, parent, idx) + tw.writeExprsKotlinType(id, type.kotlinResult.id) + tw.writeHasLocation(id, tw.getLocation(c)) + tw.writeCallableEnclosingExpr(id, callable) + tw.writeStatementEnclosingExpr(id, enclosingStmt) + } else { + logger.errorElement("Unexpected enum type rep ${enumType.javaClass}", c) + } } fun binopReceiver(id: Label, receiver: IrExpression?, receiverDescription: String) { @@ -2177,30 +2213,47 @@ open class KotlinFileExtractor( extractRawMethodAccess(getter, c, callable, parent, idx, enclosingStmt, listOf(), null, ext, typeArguments) } } - isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "iterator") && c.origin == IrStatementOrigin.FOR_LOOP_ITERATOR -> { - findTopLevelFunctionOrWarn("kotlin.jvm.internal.iterator", "kotlin.jvm.internal.ArrayIteratorKt", c)?.let { iteratorFn -> + isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "iterator") -> { + val parentClass = target.parent + if (parentClass !is IrClass) { + logger.errorElement("Iterator parent is not a class", c) + return + } + + var typeFilter = if (isGenericArrayType(parentClass.name.asString())) { + "kotlin.jvm.internal.ArrayIteratorKt" + } else { + "kotlin.jvm.internal.ArrayIteratorsKt" + } + + findTopLevelFunctionOrWarn("kotlin.jvm.internal.iterator", typeFilter, arrayOf(parentClass.kotlinFqName.asString()), c)?.let { iteratorFn -> val dispatchReceiver = c.dispatchReceiver if (dispatchReceiver == null) { logger.errorElement("No dispatch receiver found for array iterator call", c) } else { - val typeArgs = (dispatchReceiver.type as IrSimpleType).arguments.map { - when(it) { - is IrTypeProjection -> it.type - else -> pluginContext.irBuiltIns.anyNType + val drType = dispatchReceiver.type + if (drType !is IrSimpleType) { + logger.errorElement("Dispatch receiver with unexpected type rep found for array iterator call: ${drType.javaClass}", c) + } else { + val typeArgs = drType.arguments.map { + when(it) { + is IrTypeProjection -> it.type + else -> pluginContext.irBuiltIns.anyNType + } } + extractRawMethodAccess(iteratorFn, c, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, typeArgs) } - extractRawMethodAccess(iteratorFn, c, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, typeArgs) } } } - isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "get") && c.origin == IrStatementOrigin.GET_ARRAY_ELEMENT -> { + isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "get") && c.origin == IrStatementOrigin.GET_ARRAY_ELEMENT && c.dispatchReceiver != null -> { val id = tw.getFreshIdLabel() val type = useType(c.type) tw.writeExprs_arrayaccess(id, type.javaResult.id, parent, idx) tw.writeExprsKotlinType(id, type.kotlinResult.id) binopDisp(id) } - isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "set") && c.origin == IrStatementOrigin.EQ -> { + isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "set") && c.origin == IrStatementOrigin.EQ && c.dispatchReceiver != null -> { val array = c.dispatchReceiver val arrayIdx = c.getValueArgument(0) val assignedValue = c.getValueArgument(1) @@ -2273,10 +2326,10 @@ open class KotlinFileExtractor( logger.errorElement("Argument to dataClassArrayMemberToString not a class", c) return } - val realCallee = javaUtilArrays?.declarations?.find { decl -> - decl is IrFunction && decl.name.asString() == "toString" && decl.valueParameters.size == 1 && + val realCallee = javaUtilArrays?.declarations?.findSubType { decl -> + decl.name.asString() == "toString" && decl.valueParameters.size == 1 && decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true - } as IrFunction? + } if (realCallee == null) { logger.errorElement("Couldn't find a java.lang.Arrays.toString method matching class ${realArrayClass.owner.name}", c) } else { @@ -2300,10 +2353,10 @@ open class KotlinFileExtractor( logger.errorElement("Argument to dataClassArrayMemberHashCode not a class", c) return } - val realCallee = javaUtilArrays?.declarations?.find { decl -> - decl is IrFunction && decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 && + val realCallee = javaUtilArrays?.declarations?.findSubType { decl -> + decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 && decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true - } as IrFunction? + } if (realCallee == null) { logger.errorElement("Couldn't find a java.lang.Arrays.hashCode method matching class ${realArrayClass.owner.name}", c) } else { @@ -2380,18 +2433,27 @@ open class KotlinFileExtractor( callable: Label, enclosingStmt: Label ) { - val isAnonymous = e.type.isAnonymous + val eType = e.type + if (eType !is IrSimpleType) { + logger.errorElement("Constructor call has non-simple type ${eType.javaClass}", e) + return + } + val isAnonymous = eType.isAnonymous val type: TypeResults = if (isAnonymous) { if (e.typeArgumentsCount > 0) { - logger.warn("Unexpected type arguments for anonymous class constructor call") + logger.warnElement("Unexpected type arguments (${e.typeArgumentsCount}) for anonymous class constructor call", e) + } + val c = eType.classifier.owner + if (c !is IrClass) { + logger.errorElement("Anonymous constructor call type not a class (${c.javaClass})", e) + return } - val c = (e.type as IrSimpleType).classifier.owner as IrClass useAnonymousClass(c) } else { - useType(e.type) + useType(eType) } val locId = tw.getLocation(e) - val id = extractNewExpr(e.symbol.owner, (e.type as? IrSimpleType)?.arguments, type, locId, parent, idx, callable, enclosingStmt) + val id = extractNewExpr(e.symbol.owner, eType.arguments, type, locId, parent, idx, callable, enclosingStmt) if (isAnonymous) { tw.writeIsAnonymClass(type.javaResult.id.cast(), id) @@ -2405,8 +2467,11 @@ open class KotlinFileExtractor( } val typeAccessType = if (isAnonymous) { - val c = (e.type as IrSimpleType).classifier.owner as IrClass - if (c.superTypes.size == 1) { + val c = eType.classifier.owner + if (c !is IrClass) { + logger.warnElement("Anonymous type not a class (${c.javaClass})", e) + } + if ((c as? IrClass)?.superTypes?.size == 1) { useType(c.superTypes.first()) } else { useType(pluginContext.irBuiltIns.anyType) @@ -2416,7 +2481,7 @@ open class KotlinFileExtractor( } if (e is IrConstructorCall) { - extractConstructorTypeAccess(e.type, typeAccessType, e.symbol, locId, id, -3, callable, enclosingStmt) + extractConstructorTypeAccess(eType, typeAccessType, e.symbol, locId, id, -3, callable, enclosingStmt) } else { val typeAccessId = extractTypeAccess(typeAccessType, locId, id, -3, callable, enclosingStmt) @@ -2425,9 +2490,6 @@ open class KotlinFileExtractor( } } - // todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain - private val declarationStack: Stack = Stack() - abstract inner class StmtExprParent { abstract fun stmt(e: IrExpression, callable: Label): StmtParent abstract fun expr(e: IrExpression, callable: Label): ExprParent @@ -2520,8 +2582,8 @@ open class KotlinFileExtractor( indexVarDecl.initializer?.let { indexVarInitializer -> (e.statements[2] as? IrCall)?.let { arraySetCall -> if (isFunction(arraySetCall.symbol.owner, "kotlin", "(some array type)", { isArrayType(it) }, "set")) { - val updateRhs = arraySetCall.getValueArgument(1) - if (updateRhs == null) { + val updateRhs0 = arraySetCall.getValueArgument(1) + if (updateRhs0 == null) { logger.errorElement("Update RHS not found", e) return false } @@ -2534,7 +2596,7 @@ open class KotlinFileExtractor( receiverVal -> receiverVal.symbol.owner == arrayVarDecl.symbol.owner } ?: false }, - updateRhs + updateRhs0 )?.let { updateRhs -> val origin = e.origin if (origin == null) { @@ -2601,8 +2663,15 @@ open class KotlinFileExtractor( val irCallable = declarationStack.peek() - val delegatingClass = e.symbol.owner.parent as IrClass - val currentClass = irCallable.parent as IrClass + val delegatingClass = e.symbol.owner.parent + val currentClass = irCallable.parent + + if (delegatingClass !is IrClass) { + logger.warnElement("Delegating class isn't a class: " + delegatingClass.javaClass, e) + } + if (currentClass !is IrClass) { + logger.warnElement("Current class isn't a class: " + currentClass.javaClass, e) + } val id: Label if (delegatingClass != currentClass) { @@ -3036,7 +3105,14 @@ open class KotlinFileExtractor( extractTypeOperatorCall(e, callable, exprParent.parent, exprParent.idx, exprParent.enclosingStmt) } is IrVararg -> { - logger.errorElement("Unexpected IrVararg", e) + var spread = e.elements.getOrNull(0) as? IrSpreadElement + if (spread == null || e.elements.size != 1) { + logger.errorElement("Unexpected IrVararg", e) + return + } + // There are lowered IR cases when the vararg expression is not within a call, such as + // val temp0 = [*expr] + extractExpression(spread.expression, callable, parent) } is IrGetObjectValue -> { // For `object MyObject { ... }`, the .class has an @@ -3345,15 +3421,11 @@ open class KotlinFileExtractor( data class ReceiverInfo(val receiver: IrExpression, val type: IrType, val field: Label, val indexOffset: Int) - private fun makeReceiverInfo(callableReferenceExpr: IrCallableReference, receiver: IrExpression?, indexOffset: Int): ReceiverInfo? { + private fun makeReceiverInfo(receiver: IrExpression?, indexOffset: Int): ReceiverInfo? { if (receiver == null) { return null } val type = receiver.type - if (type == null) { - logger.warnElement("Receiver has no type", callableReferenceExpr) - return null - } val field: Label = tw.getFreshIdLabel() return ReceiverInfo(receiver, type, field, indexOffset) } @@ -3366,8 +3438,8 @@ open class KotlinFileExtractor( : GeneratedClassHelper(locId, ids) { // Only one of the receivers can be non-null, but we defensively handle the case when both are null anyway - private val dispatchReceiverInfo = makeReceiverInfo(callableReferenceExpr, callableReferenceExpr.dispatchReceiver, 0) - private val extensionReceiverInfo = makeReceiverInfo(callableReferenceExpr, callableReferenceExpr.extensionReceiver, if (dispatchReceiverInfo == null) 0 else 1) + private val dispatchReceiverInfo = makeReceiverInfo(callableReferenceExpr.dispatchReceiver, 0) + private val extensionReceiverInfo = makeReceiverInfo(callableReferenceExpr.extensionReceiver, if (dispatchReceiverInfo == null) 0 else 1) fun extractReceiverField() { val firstAssignmentStmtIdx = 1 @@ -3658,6 +3730,11 @@ open class KotlinFileExtractor( logger.errorElement("Cannot find class for kPropertyType. ${kPropertyType.classFqName?.asString()}", propertyReferenceExpr) return } + val parameterTypes = kPropertyType.arguments.map { it as? IrType }.requireNoNullsOrNull() + if (parameterTypes == null) { + logger.errorElement("Unexpected: Non-IrType parameter.", propertyReferenceExpr) + return + } val locId = tw.getLocation(propertyReferenceExpr) @@ -3670,15 +3747,14 @@ open class KotlinFileExtractor( constructorBlock = tw.getFreshIdLabel() ) - val currentDeclaration = declarationStack.peek() + val declarationParent = declarationStack.peekAsDeclarationParent(propertyReferenceExpr) ?: return val prefix = if (kPropertyClass.owner.name.asString().startsWith("KMutableProperty")) "Mutable" else "" val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.${prefix}PropertyReference${kPropertyType.arguments.size - 1}"))?.owner?.typeWith() ?: pluginContext.irBuiltIns.anyType - val classId = extractGeneratedClass(ids, listOf(baseClass, kPropertyType), locId, currentDeclaration) + val classId = extractGeneratedClass(ids, listOf(baseClass, kPropertyType), locId, propertyReferenceExpr, declarationParent) val helper = PropertyReferenceHelper(propertyReferenceExpr, locId, ids) - val parameterTypes = kPropertyType.arguments.map { it as IrType } helper.extractReceiverField() @@ -3825,7 +3901,11 @@ open class KotlinFileExtractor( return } - val parameterTypes = type.arguments.map { it as IrType } + val parameterTypes = type.arguments.map { it as? IrType }.requireNoNullsOrNull() + if (parameterTypes == null) { + logger.errorElement("Unexpected: Non-IrType parameter.", functionReferenceExpr) + return + } val dispatchReceiverIdx: Int val expressionTypeArguments: List @@ -3874,12 +3954,12 @@ open class KotlinFileExtractor( if (fnInterfaceType == null) { logger.warnElement("Cannot find functional interface type for function reference", functionReferenceExpr) } else { - val currentDeclaration = declarationStack.peek() + val declarationParent = declarationStack.peekAsDeclarationParent(functionReferenceExpr) ?: return // `FunctionReference` base class is required, because that's implementing `KFunction`. val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.FunctionReference"))?.owner?.typeWith() ?: pluginContext.irBuiltIns.anyType - val classId = extractGeneratedClass(ids, listOf(baseClass, fnInterfaceType), locId, currentDeclaration) + val classId = extractGeneratedClass(ids, listOf(baseClass, fnInterfaceType), locId, functionReferenceExpr, declarationParent) helper.extractReceiverField() @@ -4233,6 +4313,8 @@ open class KotlinFileExtractor( * Extracts a type access expression and its child type access expressions in case of a generic type. Nested generics are also handled. */ private fun extractTypeAccessRecursive(t: IrType, location: Label, parent: Label, idx: Int, enclosingCallable: Label, enclosingStmt: Label, typeContext: TypeContext = TypeContext.OTHER): Label { + // TODO: `useType` substitutes types to their java equivalent, and sometimes that also means changing the number of type arguments. The below logic doesn't take this into account. + // For example `KFunction2` becomes `KFunction` with three child type access expressions: `Int`, `Double`, `String`. val typeAccessId = extractTypeAccess(useType(t, typeContext), location, parent, idx, enclosingCallable, enclosingStmt) if (t is IrSimpleType) { extractTypeArguments(t.arguments.filterIsInstance(), location, typeAccessId, enclosingCallable, enclosingStmt) @@ -4452,7 +4534,7 @@ open class KotlinFileExtractor( return } - val invokeMethod = functionType.classOrNull?.owner?.declarations?.filterIsInstance()?.find { it.name.asString() == OperatorNameConventions.INVOKE.asString()} + val invokeMethod = functionType.classOrNull?.owner?.declarations?.findSubType { it.name.asString() == OperatorNameConventions.INVOKE.asString()} if (invokeMethod == null) { logger.errorElement("Couldn't find `invoke` method on functional interface.", e) return @@ -4463,7 +4545,7 @@ open class KotlinFileExtractor( logger.errorElement("Expected to find SAM conversion to IrClass. Found '${typeOwner.javaClass}' instead. Can't implement SAM interface.", e) return } - val samMember = typeOwner.declarations.filterIsInstance().find { it is IrOverridableMember && it.modality == Modality.ABSTRACT } + val samMember = typeOwner.declarations.findSubType { it is IrOverridableMember && it.modality == Modality.ABSTRACT } if (samMember == null) { logger.errorElement("Couldn't find SAM member in type '${typeOwner.kotlinFqName.asString()}'. Can't implement SAM interface.", e) return @@ -4481,8 +4563,8 @@ open class KotlinFileExtractor( val locId = tw.getLocation(e) val helper = GeneratedClassHelper(locId, ids) - val currentDeclaration = declarationStack.peek() - val classId = extractGeneratedClass(ids, listOf(pluginContext.irBuiltIns.anyType, e.typeOperand), locId, currentDeclaration) + val declarationParent = declarationStack.peekAsDeclarationParent(e) ?: return + val classId = extractGeneratedClass(ids, listOf(pluginContext.irBuiltIns.anyType, e.typeOperand), locId, e, declarationParent) // add field val fieldId = tw.getFreshIdLabel() @@ -4624,7 +4706,8 @@ open class KotlinFileExtractor( ids: GeneratedClassLabels, superTypes: List, locId: Label, - currentDeclaration: IrDeclaration + elementToReportOn: IrElement, + declarationParent: IrDeclarationParent ): Label { // Write class val id = ids.type.javaResult.id.cast() @@ -4647,23 +4730,27 @@ open class KotlinFileExtractor( // Super call val baseClass = superTypes.first().classOrNull if (baseClass == null) { - logger.warnElement("Cannot find base class", currentDeclaration) + logger.warnElement("Cannot find base class", elementToReportOn) } else { - val superCallId = tw.getFreshIdLabel() - tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor) + val baseConstructor = baseClass.owner.declarations.findSubType { it.symbol is IrConstructorSymbol } + if (baseConstructor == null) { + logger.warnElement("Cannot find base constructor", elementToReportOn) + } else { + val superCallId = tw.getFreshIdLabel() + tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor) - val baseConstructor = baseClass.owner.declarations.find { it is IrFunction && it.symbol is IrConstructorSymbol } - val baseConstructorId = useFunction(baseConstructor as IrFunction) + val baseConstructorId = useFunction(baseConstructor) - tw.writeHasLocation(superCallId, locId) - tw.writeCallableBinding(superCallId.cast(), baseConstructorId) + tw.writeHasLocation(superCallId, locId) + tw.writeCallableBinding(superCallId.cast(), baseConstructorId) + } } addModifiers(id, "final") addVisibilityModifierToLocalOrAnonymousClass(id) extractClassSupertypes(superTypes, listOf(), id, inReceiverContext = true) - extractEnclosingClass(currentDeclaration, id, locId, listOf()) + extractEnclosingClass(declarationParent, id, null, locId, listOf()) return id } @@ -4675,7 +4762,7 @@ open class KotlinFileExtractor( with("generated class", localFunction) { val ids = getLocallyVisibleFunctionLabels(localFunction) - val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction) + val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction, localFunction.parent) // Extract local function as a member extractFunction(localFunction, id, extractBody = true, extractMethodAndParameterTypeAccesses = true, null, listOf()) @@ -4684,6 +4771,34 @@ open class KotlinFileExtractor( } } + // todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain + private val declarationStack = DeclarationStack() + + private inner class DeclarationStack { + private val stack: Stack = Stack() + + fun push(item: IrDeclaration) = stack.push(item) + + fun pop() = stack.pop() + + fun isEmpty() = stack.isEmpty() + + fun peek() = stack.peek() + + fun peekAsDeclarationParent(elementToReportOn: IrElement): IrDeclarationParent? { + val trapWriter = tw + if (isEmpty() && trapWriter is SourceFileTrapWriter) { + // If the current declaration is used as a parent, we might end up with an empty stack. In this case, the source file is the parent. + return trapWriter.irFile + } + + val dp = peek() as? IrDeclarationParent + if (dp == null) { + logger.errorElement("Couldn't find current declaration parent", elementToReportOn) + } + return dp + } + } private inner class DeclarationStackAdjuster(declaration: IrDeclaration): Closeable { init { diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index db25b2b84a7..8a3dd214837 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -220,7 +220,7 @@ open class KotlinUsesExtractor( val extractedTypeArgs = when { extractClass.symbol.isKFunction() && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last()) extractClass.fqNameWhenAvailable == FqName("kotlin.jvm.functions.FunctionN") && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last()) - typeArgs != null && isUnspecialised(c, typeArgs) -> listOf() + typeArgs != null && isUnspecialised(c, typeArgs, logger) -> listOf() else -> typeArgs } @@ -326,11 +326,11 @@ open class KotlinUsesExtractor( if (replacementClass === parentClass) return f return globalExtensionState.syntheticToRealFunctionMap.getOrPut(f) { - val result = replacementClass.declarations.find { replacementDecl -> - replacementDecl is IrSimpleFunction && replacementDecl.name == f.name && replacementDecl.valueParameters.size == f.valueParameters.size && replacementDecl.valueParameters.zip(f.valueParameters).all { + val result = replacementClass.declarations.findSubType { replacementDecl -> + replacementDecl.name == f.name && replacementDecl.valueParameters.size == f.valueParameters.size && replacementDecl.valueParameters.zip(f.valueParameters).all { erase(it.first.type) == erase(it.second.type) } - } as IrFunction? + } if (result == null) { logger.warn("Failed to replace synthetic class function ${f.name}") } else { @@ -351,9 +351,9 @@ open class KotlinUsesExtractor( if (replacementClass === parentClass) return f return globalExtensionState.syntheticToRealFieldMap.getOrPut(f) { - val result = replacementClass.declarations.find { replacementDecl -> - replacementDecl is IrField && replacementDecl.name == f.name - } as IrField? + val result = replacementClass.declarations.findSubType { replacementDecl -> + replacementDecl.name == f.name + } if (result == null) { logger.warn("Failed to replace synthetic class field ${f.name}") } else { @@ -479,7 +479,7 @@ open class KotlinUsesExtractor( fun useSimpleTypeClass(c: IrClass, args: List?, hasQuestionMark: Boolean): TypeResults { if (c.isAnonymousObject) { args?.let { - if (it.isNotEmpty() && !isUnspecialised(c, it)) { + if (it.isNotEmpty() && !isUnspecialised(c, it, logger)) { logger.error("Unexpected specialised instance of generic anonymous class") } } @@ -539,15 +539,52 @@ open class KotlinUsesExtractor( ) } - private fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults { + data class ArrayInfo(val elementTypeResults: TypeResults, + val componentTypeResults: TypeResults, + val dimensions: Int) - // Ensure we extract Array as Integer[], not int[], for example: - fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type + /** + * `t` is somewhere in a stack of array types, or possibly the + * element type of the innermost array. For example, in + * `Array>`, we will be called with `t` being + * `Array>`, then `Array`, then `Int`. + * `isPrimitiveArray` is true if we are immediately nested + * inside a primitive array. + */ + private fun useArrayType(t: IrType, isPrimitiveArray: Boolean): ArrayInfo { - val componentTypeResults = useType(nullableIfNotPrimitive(componentType)) - val elementTypeLabel = useType(nullableIfNotPrimitive(elementType)).javaResult.id + if (!t.isBoxedArray && !t.isPrimitiveArray()) { + val nullableT = if (t.isPrimitiveType() && !isPrimitiveArray) t.makeNullable() else t + val typeResults = useType(nullableT) + return ArrayInfo(typeResults, typeResults, 0) + } - val javaShortName = componentTypeResults.javaResult.shortName + "[]" + if (t !is IrSimpleType) { + logger.error("Unexpected non-simple array type: ${t.javaClass}") + return ArrayInfo(extractErrorType(), extractErrorType(), 0) + } + + val arrayClass = t.classifier.owner + if (arrayClass !is IrClass) { + logger.error("Unexpected owner type for array type: ${arrayClass.javaClass}") + return ArrayInfo(extractErrorType(), extractErrorType(), 0) + } + + // Because Java's arrays are covariant, Kotlin will render + // Array as Object[], Array> as Object[][] etc. + val elementType = if ((t.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) { + pluginContext.irBuiltIns.anyType + } else { + t.getArrayElementType(pluginContext.irBuiltIns) + } + + val recInfo = useArrayType(elementType, t.isPrimitiveArray()) + + val javaShortName = recInfo.componentTypeResults.javaResult.shortName + "[]" + val kotlinShortName = recInfo.componentTypeResults.kotlinResult.shortName + "[]" + val elementTypeLabel = recInfo.elementTypeResults.javaResult.id + val componentTypeLabel = recInfo.componentTypeResults.javaResult.id + val dimensions = recInfo.dimensions + 1 val id = tw.getLabelFor("@\"array;$dimensions;{${elementTypeLabel}}\"") { tw.writeArrays( @@ -555,9 +592,9 @@ open class KotlinUsesExtractor( javaShortName, elementTypeLabel, dimensions, - componentTypeResults.javaResult.id) + componentTypeLabel) - extractClassSupertypes(arrayType.classifier.owner as IrClass, it, ExtractSupertypesMode.Specialised(arrayType.arguments)) + extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(t.arguments)) // array.length val length = tw.getLabelFor("@\"field;{$it};length\"") @@ -568,7 +605,7 @@ open class KotlinUsesExtractor( // Note we will only emit one `clone()` method per Java array type, so we choose `Array` as its Kotlin // return type, where C is the component type with any nested arrays themselves invariant and nullable. - val kotlinCloneReturnType = getInvariantNullableArrayType(arrayType).makeNullable() + val kotlinCloneReturnType = getInvariantNullableArrayType(t).makeNullable() val kotlinCloneReturnTypeLabel = useType(kotlinCloneReturnType).kotlinResult.id val clone = tw.getLabelFor("@\"callable;{$it}.clone(){$it}\"") @@ -579,11 +616,15 @@ open class KotlinUsesExtractor( val javaResult = TypeResult( id, - componentTypeResults.javaResult.signature + "[]", + recInfo.componentTypeResults.javaResult.signature + "[]", javaShortName) + val kotlinResult = TypeResult( + fakeKotlinType(), + recInfo.componentTypeResults.kotlinResult.signature + "[]", + kotlinShortName) + val typeResults = TypeResults(javaResult, kotlinResult) - val arrayClassResult = useSimpleTypeClass(arrayType.classifier.owner as IrClass, arrayType.arguments, arrayType.hasQuestionMark) - return TypeResults(javaResult, arrayClassResult.kotlinResult) + return ArrayInfo(recInfo.elementTypeResults, typeResults, dimensions) } enum class TypeContext { @@ -609,7 +650,7 @@ open class KotlinUsesExtractor( otherIsPrimitive: Boolean, javaClass: IrClass, kotlinPackageName: String, kotlinClassName: String): TypeResults { - val javaResult = if ((context == TypeContext.RETURN || (context == TypeContext.OTHER && otherIsPrimitive)) && !s.hasQuestionMark && primitiveName != null) { + val javaResult = if ((context == TypeContext.RETURN || (context == TypeContext.OTHER && otherIsPrimitive)) && !s.isNullable() && primitiveName != null) { val label: Label = tw.getLabelFor("@\"type;$primitiveName\"", { tw.writePrimitives(it, primitiveName) }) @@ -619,7 +660,7 @@ open class KotlinUsesExtractor( } val kotlinClassId = useClassInstance(kotlinClass, listOf()).typeResult.id val kotlinResult = if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") else - if (s.hasQuestionMark) { + if (s.isNullable()) { val kotlinSignature = "$kotlinPackageName.$kotlinClassName?" // TODO: Is this right? val kotlinLabel = "@\"kt_type;nullable;$kotlinPackageName.$kotlinClassName\"" val kotlinId: Label = tw.getLabelFor(kotlinLabel, { @@ -637,66 +678,39 @@ open class KotlinUsesExtractor( return TypeResults(javaResult, kotlinResult) } + val owner = s.classifier.owner val primitiveInfo = primitiveTypeMapping.getPrimitiveInfo(s) when { - primitiveInfo != null -> return primitiveType( - s.classifier.owner as IrClass, - primitiveInfo.primitiveName, primitiveInfo.otherIsPrimitive, - primitiveInfo.javaClass, - primitiveInfo.kotlinPackageName, primitiveInfo.kotlinClassName - ) + primitiveInfo != null -> { + if (owner is IrClass) { + return primitiveType( + owner, + primitiveInfo.primitiveName, primitiveInfo.otherIsPrimitive, + primitiveInfo.javaClass, + primitiveInfo.kotlinPackageName, primitiveInfo.kotlinClassName + ) + } else { + logger.error("Got primitive info for non-class (${owner.javaClass}) for ${s.render()}") + return extractErrorType() + } + } (s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> { - - fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrSimpleType = - if (dimensions == 0) - pluginContext.irBuiltIns.anyType as IrSimpleType - else - t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection) - .let { oldArg -> - listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance)) - } - }.buildSimpleType() - - var componentType = s.getArrayElementType(pluginContext.irBuiltIns) - var isPrimitiveArray = false - var dimensions = 0 - var elementType: IrType = s - while (elementType.isBoxedArray || elementType.isPrimitiveArray()) { - dimensions++ - if (elementType.isPrimitiveArray()) - isPrimitiveArray = true - if (((elementType as IrSimpleType).arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) { - // Because Java's arrays are covariant, Kotlin will render Array as Object[], Array> as Object[][] etc. - componentType = replaceComponentTypeWithAny(s, dimensions - 1) - elementType = pluginContext.irBuiltIns.anyType as IrSimpleType - break - } - elementType = elementType.getArrayElementType(pluginContext.irBuiltIns) - } - - return useArrayType( - s, - componentType, - elementType, - dimensions, - isPrimitiveArray - ) + val arrayInfo = useArrayType(s, false) + return arrayInfo.componentTypeResults } - s.classifier.owner is IrClass -> { - val classifier: IrClassifierSymbol = s.classifier - val cls: IrClass = classifier.owner as IrClass + owner is IrClass -> { val args = if (s.isRawType()) null else s.arguments - return useSimpleTypeClass(cls, args, s.hasQuestionMark) + return useSimpleTypeClass(owner, args, s.isNullable()) } - s.classifier.owner is IrTypeParameter -> { - val javaResult = useTypeParameter(s.classifier.owner as IrTypeParameter) + owner is IrTypeParameter -> { + val javaResult = useTypeParameter(owner) val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong val kotlinResult = if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") else - if (s.hasQuestionMark) { + if (s.isNullable()) { val kotlinSignature = "${javaResult.signature}?" // TODO: Wrong val kotlinLabel = "@\"kt_type;nullable;type_param\"" // TODO: Wrong val kotlinId: Label = tw.getLabelFor(kotlinLabel, { @@ -905,10 +919,17 @@ open class KotlinUsesExtractor( } private fun extendsAdditionAllowed(t: IrType) = - if (t.isBoxedArray) - arrayExtendsAdditionAllowed(t as IrSimpleType) - else + if (t.isBoxedArray) { + if (t is IrSimpleType) { + arrayExtendsAdditionAllowed(t) + } else { + logger.warn("Boxed array of unexpected kind ${t.javaClass}") + // Return false, for no particular reason + false + } + } else { ((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true + } private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean) = when { @@ -1097,7 +1118,7 @@ open class KotlinUsesExtractor( return f.returnType } - val otherKeySet = parentClass.declarations.filterIsInstance().find { it.name.asString() == "keySet" && it.valueParameters.size == 1 } + val otherKeySet = parentClass.declarations.findSubType { it.name.asString() == "keySet" && it.valueParameters.size == 1 } ?: return f.returnType return otherKeySet.returnType.codeQlWithHasQuestionMark(false) @@ -1117,10 +1138,6 @@ open class KotlinUsesExtractor( // Note not using `parentsWithSelf` as that only works if `d` is an IrDeclarationParent d.parents.any { (it as? IrAnnotationContainer)?.hasAnnotation(jvmWildcardSuppressionAnnotaton) == true } - protected fun IrFunction.isLocalFunction(): Boolean { - return this.visibility == DescriptorVisibilities.LOCAL - } - /** * Class to hold labels for generated classes around local functions, lambdas, function references, and property references. */ @@ -1162,6 +1179,14 @@ open class KotlinUsesExtractor( return res } + fun getExistingLocallyVisibleFunctionLabel(f: IrFunction): Label? { + if (!f.isLocalFunction()){ + return null + } + + return tw.lm.locallyVisibleFunctionLabelMapping[f]?.function + } + // These are classes with Java equivalents, but whose methods don't all exist on those Java equivalents-- // for example, the numeric classes define arithmetic functions (Int.plus, Long.or and so on) that lower to // primitive arithmetic on the JVM, but which we extract as calls to reflect the source syntax more closely. @@ -1169,17 +1194,17 @@ open class KotlinUsesExtractor( "kotlin.Boolean", "kotlin.Byte", "kotlin.Char", "kotlin.Double", "kotlin.Float", "kotlin.Int", "kotlin.Long", "kotlin.Number", "kotlin.Short" ) - private fun kotlinFunctionToJavaEquivalent(f: IrFunction, noReplace: Boolean) = + private fun kotlinFunctionToJavaEquivalent(f: IrFunction, noReplace: Boolean): IrFunction = if (noReplace) f else f.parentClassOrNull?.let { parentClass -> getJavaEquivalentClass(parentClass)?.let { javaClass -> - if (javaClass != parentClass) + if (javaClass != parentClass) { + val jvmName = getJvmName(f) ?: f.name.asString() // Look for an exact type match... - javaClass.declarations.find { decl -> - decl is IrFunction && - decl.name == f.name && + javaClass.declarations.findSubType { decl -> + decl.name.asString() == jvmName && decl.valueParameters.size == f.valueParameters.size && // Note matching by classifier not the whole type so that generic arguments are allowed to differ, // as they always will for method type parameters occurring in parameter types (e.g. toArray(T[] array) @@ -1187,23 +1212,20 @@ open class KotlinUsesExtractor( decl.valueParameters.zip(f.valueParameters).all { p -> p.first.type.classifierOrNull == p.second.type.classifierOrNull } } ?: // Or if there is none, look for the only viable overload - javaClass.declarations.singleOrNull { decl -> - decl is IrFunction && - decl.name == f.name && + javaClass.declarations.singleOrNullSubType { decl -> + decl.name.asString() == jvmName && decl.valueParameters.size == f.valueParameters.size } ?: // Or check property accessors: - if (f.isAccessor) { - val prop = javaClass.declarations.filterIsInstance().find { decl -> - decl.name == (f.propertyIfAccessor as IrProperty).name + (f.propertyIfAccessor as? IrProperty)?.let { kotlinProp -> + val javaProp = javaClass.declarations.findSubType { decl -> + decl.name == kotlinProp.name } - if (prop?.getter?.name == f.name) - prop.getter - else if (prop?.setter?.name == f.name) - prop.setter + if (javaProp?.getter?.name == f.name) + javaProp.getter + else if (javaProp?.setter?.name == f.name) + javaProp.setter else null - } else { - null } ?: run { val parentFqName = parentClass.fqNameWhenAvailable?.asString() if (!expectedMissingEquivalents.contains(parentFqName)) { @@ -1211,10 +1233,11 @@ open class KotlinUsesExtractor( } null } + } else null } - } as IrFunction? ?: f + } ?: f fun useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List? = null, noReplace: Boolean = false): Label { return useFunction(f, null, classTypeArgsIncludingOuterClasses, noReplace) @@ -1416,12 +1439,11 @@ open class KotlinUsesExtractor( for(t in subbedSupertypes) { when(t) { is IrSimpleType -> { - when (t.classifier.owner) { + val owner = t.classifier.owner + when (owner) { is IrClass -> { - val classifier: IrClassifierSymbol = t.classifier - val tcls: IrClass = classifier.owner as IrClass val typeArgs = if (t.arguments.isNotEmpty() && mode is ExtractSupertypesMode.Raw) null else t.arguments - val l = useClassInstance(tcls, typeArgs, inReceiverContext).typeResult.id + val l = useClassInstance(owner, typeArgs, inReceiverContext).typeResult.id tw.writeExtendsReftype(id, l) } else -> { @@ -1459,13 +1481,13 @@ open class KotlinUsesExtractor( return eraseTypeParameter(owner) } - if (t.isArray() || t.isNullableArray()) { - val elementType = t.getArrayElementType(pluginContext.irBuiltIns) - val erasedElementType = erase(elementType) - return (classifier as IrClassSymbol).typeWith(erasedElementType).codeQlWithHasQuestionMark(t.hasQuestionMark) - } - if (owner is IrClass) { + if (t.isArray() || t.isNullableArray()) { + val elementType = t.getArrayElementType(pluginContext.irBuiltIns) + val erasedElementType = erase(elementType) + return owner.typeWith(erasedElementType).codeQlWithHasQuestionMark(t.isNullable()) + } + return if (t.arguments.isNotEmpty()) t.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) else diff --git a/java/kotlin-extractor/src/main/kotlin/Label.kt b/java/kotlin-extractor/src/main/kotlin/Label.kt index 10459319a76..5a116bb0115 100644 --- a/java/kotlin-extractor/src/main/kotlin/Label.kt +++ b/java/kotlin-extractor/src/main/kotlin/Label.kt @@ -6,8 +6,8 @@ import java.io.StringWriter /** * This represents a label (`#...`) in a TRAP file. */ -interface Label { - fun cast(): Label { +interface Label { + fun cast(): Label { @Suppress("UNCHECKED_CAST") return this as Label } @@ -17,7 +17,7 @@ interface Label { * The label `#i`, e.g. `#123`. Most labels we generate are of this * form. */ -class IntLabel(val i: Int): Label { +class IntLabel(val i: Int): Label { override fun toString(): String = "#$i" } @@ -26,6 +26,6 @@ class IntLabel(val i: Int): Label { * shared between different components (e.g. when both the interceptor * and the extractor need to refer to the same label). */ -class StringLabel(val name: String): Label { +class StringLabel(val name: String): Label { override fun toString(): String = "#$name" } diff --git a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt index a4902dc10c9..2fae0a1e5d9 100644 --- a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt +++ b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt @@ -26,7 +26,7 @@ class TrapLabelManager { private var nextInt: Int = 100 /** Returns a fresh label. */ - fun getFreshLabel(): Label { + fun getFreshLabel(): Label { return IntLabel(nextInt++) } @@ -64,7 +64,7 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa * `getLabelFor` instead, which allows non-existent labels to be * initialised. */ - fun getExistingLabelFor(key: String): Label? { + fun getExistingLabelFor(key: String): Label? { return lm.labelMapping.get(key)?.cast() } /** @@ -73,7 +73,7 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa * is run on it, and it is returned. */ @JvmOverloads // Needed so Java can call a method with an optional argument - fun getLabelFor(key: String, initialise: (Label) -> Unit = {}): Label { + fun getLabelFor(key: String, initialise: (Label) -> Unit = {}): Label { val maybeLabel: Label? = getExistingLabelFor(key) if(maybeLabel == null) { val label: Label = lm.getFreshLabel() @@ -89,7 +89,7 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa /** * Returns a label for a fresh ID (i.e. a new label bound to `*`). */ - fun getFreshIdLabel(): Label { + fun getFreshIdLabel(): Label { val label: Label = lm.getFreshLabel() writeTrap("$label = *\n") return label @@ -319,7 +319,7 @@ class SourceFileTrapWriter ( lm: TrapLabelManager, bw: BufferedWriter, diagnosticTrapWriter: TrapWriter?, - irFile: IrFile, + val irFile: IrFile, populateFileTables: Boolean) : FileTrapWriter(loggerBase, lm, bw, diagnosticTrapWriter, irFile.path, populateFileTables) { diff --git a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt index 03f032f8810..c1a1d566a74 100644 --- a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt @@ -2,11 +2,15 @@ package com.github.codeql.comments import com.github.codeql.* import com.github.codeql.utils.IrVisitorLookup +import com.github.codeql.utils.isLocalFunction import com.github.codeql.utils.versions.Psi2Ir import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtVisitor @@ -89,38 +93,88 @@ class CommentExtractor(private val fileExtractor: KotlinFileExtractor, private v file.accept(IrVisitorLookup(psi2Ir, ownerPsi, file), owners) for (ownerIr in owners) { - val ownerLabel = - if (ownerIr == file) - fileLabel - else { - if (ownerIr is IrValueParameter && ownerIr.index == -1) { - // Don't attribute comments to the implicit `this` parameter of a function. - continue - } - val label: String - val existingLabel = if (ownerIr is IrVariable) { - label = "variable ${ownerIr.name.asString()}" - tw.getExistingVariableLabelFor(ownerIr) - } else { - label = fileExtractor.getLabel(ownerIr) ?: continue - tw.getExistingLabelFor(label) - } - if (existingLabel == null) { - logger.warn("Couldn't get existing label for $label") - continue - } - existingLabel - } - tw.writeKtCommentOwners(commentLabel, ownerLabel) + val ownerLabel = getLabel(ownerIr) + if (ownerLabel != null) { + tw.writeKtCommentOwners(commentLabel, ownerLabel) + } } } private fun getKDocOwner(comment: KDoc) : PsiElement? { val owner = comment.owner if (owner == null) { - logger.warn("Couldn't get owner of KDoc.") + logger.warn("Couldn't get owner of KDoc. The comment is extracted without an owner.") } return owner } + + private fun getLabel(element: IrElement): Label? { + if (element == file) + return fileLabel + + if (element is IrValueParameter && element.index == -1) { + // Don't attribute comments to the implicit `this` parameter of a function. + return null + } + + val label: String + val existingLabel = if (element is IrVariable) { + // local variables are not named globally, so we need to get them from the variable label cache + label = "variable ${element.name.asString()}" + tw.getExistingVariableLabelFor(element) + } else if (element is IrFunction && element.isLocalFunction()) { + // local functions are not named globally, so we need to get them from the local function label cache + label = "local function ${element.name.asString()}" + fileExtractor.getExistingLocallyVisibleFunctionLabel(element) + } + else { + label = getLabelForNamedElement(element) ?: return null + tw.getExistingLabelFor(label) + } + if (existingLabel == null) { + logger.warn("Couldn't get existing label for $label") + return null + } + return existingLabel + } + + private fun getLabelForNamedElement(element: IrElement) : String? { + when (element) { + is IrClass -> return fileExtractor.getClassLabel(element, listOf()).classLabel + is IrTypeParameter -> return fileExtractor.getTypeParameterLabel(element) + is IrFunction -> { + return if (element.isLocalFunction()) { + null + } else { + fileExtractor.getFunctionLabel(element, null) + } + } + is IrValueParameter -> return fileExtractor.getValueParameterLabel(element, null) + is IrProperty -> return fileExtractor.getPropertyLabel(element) + is IrField -> return fileExtractor.getFieldLabel(element) + is IrEnumEntry -> return fileExtractor.getEnumEntryLabel(element) + is IrTypeAlias -> return fileExtractor.getTypeAliasLabel(element) + + is IrAnonymousInitializer -> { + val parentClass = element.parentClassOrNull + if (parentClass == null) { + logger.warnElement("Parent of anonymous initializer is not a class", element) + return null + } + // Assign the comment to the class. The content of the `init` blocks might be extracted in multiple constructors. + return getLabelForNamedElement(parentClass) + } + + // Fresh entities, not named elements: + is IrBody -> return null + is IrExpression -> return null + + // todo add others: + else -> { + logger.warnElement("Unhandled element type found during comment extraction: ${element::class}", element) + return null + } + } } + } } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/Helpers.kt b/java/kotlin-extractor/src/main/kotlin/utils/Helpers.kt new file mode 100644 index 00000000000..c1f498beda2 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/Helpers.kt @@ -0,0 +1,8 @@ +package com.github.codeql.utils + +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.ir.declarations.IrFunction + +fun IrFunction.isLocalFunction(): Boolean { + return this.visibility == DescriptorVisibilities.LOCAL +} \ No newline at end of file diff --git a/java/kotlin-extractor/src/main/kotlin/utils/Iterable.kt b/java/kotlin-extractor/src/main/kotlin/utils/Iterable.kt new file mode 100644 index 00000000000..c21c4729d40 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/Iterable.kt @@ -0,0 +1,26 @@ +package com.github.codeql + +import org.jetbrains.kotlin.ir.declarations.IrDeclaration + +/** + * This behaves the same as Iterable.find, but requires + * that the value found is of the subtype S, and it casts + * the result for you appropriately. + */ +inline fun Iterable.findSubType( + predicate: (S) -> Boolean +): S? { + return this.find { it is S && predicate(it) } as S? +} + +/** + * This behaves the same as Iterable.singleOrNull, but + * requires that the value found is of the subtype S, and it casts + * the result for you appropriately. + */ +inline fun Iterable.singleOrNullSubType( + predicate: (S) -> Boolean +): S? { + return this.singleOrNull { it is S && predicate(it) } as S? +} + diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeResults.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeResults.kt index 7dde30cf932..428c7dab718 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeResults.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeResults.kt @@ -12,10 +12,10 @@ package com.github.codeql * `shortName` is a Java primitive name (e.g. "int"), a class short name with Java-style type arguments ("InnerClass" or * "OuterClass" or "OtherClass") or an array ("componentShortName[]"). */ -data class TypeResultGeneric(val id: Label, val signature: SignatureType, val shortName: String) { - fun cast(): TypeResult { +data class TypeResultGeneric(val id: Label, val signature: SignatureType, val shortName: String) { + fun cast(): TypeResultGeneric { @Suppress("UNCHECKED_CAST") - return this as TypeResult + return this as TypeResultGeneric } } data class TypeResultsGeneric(val javaResult: TypeResultGeneric, val kotlinResult: TypeResultGeneric) @@ -25,6 +25,6 @@ typealias TypeResultWithoutSignature = TypeResultGeneric typealias TypeResults = TypeResultsGeneric typealias TypeResultsWithoutSignatures = TypeResultsGeneric -fun TypeResult.forgetSignature(): TypeResultWithoutSignature { +fun TypeResult.forgetSignature(): TypeResultWithoutSignature { return TypeResultWithoutSignature(this.id, Unit, this.shortName) } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index e8a8b506d73..b402eee0030 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -1,6 +1,7 @@ package com.github.codeql.utils import com.github.codeql.KotlinUsesExtractor +import com.github.codeql.Logger import com.github.codeql.getJavaEquivalentClassId import com.github.codeql.utils.versions.codeQlWithHasQuestionMark import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor @@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance @@ -54,7 +56,7 @@ private fun IrSimpleType.substituteTypeArguments(substitutionMap: Map?, useContext: KotlinUsesExtractor.TypeContext, pluginContext: IrPluginContext): IrType = substitutionMap?.let { substMap -> - this.classifierOrNull?.let { typeClassifier -> + if (this is IrSimpleType) { + val typeClassifier = this.classifier substMap[typeClassifier]?.let { when(useContext) { KotlinUsesExtractor.TypeContext.RETURN -> it.upperBound(pluginContext) else -> it.lowerBound(pluginContext) } - } ?: (this as IrSimpleType).substituteTypeArguments(substMap) - } ?: this + } ?: this.substituteTypeArguments(substMap) + } else { + this + } } ?: this object RawTypeAnnotation { @@ -191,7 +196,7 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument = is IrStarProjection -> this is IrTypeProjection -> this.type.let { when(it) { - is IrSimpleType -> if (it.hasQuestionMark == b) this else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance) + is IrSimpleType -> if (it.isNullable() == b) this else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance) else -> this }} else -> this @@ -212,27 +217,34 @@ private fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boo } // Returns true if type is C where C is declared `class C { ... }` -fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List): Boolean { +fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List, logger: Logger): Boolean { + return isUnspecialised(paramsContainer, args, logger, paramsContainer) +} + +private fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List, logger: Logger, origParamsContainer: IrTypeParametersContainer): Boolean { val unspecialisedHere = paramsContainer.typeParameters.zip(args).all { paramAndArg -> (paramAndArg.second as? IrTypeProjection)?.let { // Type arg refers to the class' own type parameter? it.variance == Variance.INVARIANT && - matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first) + matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first) } ?: false } val remainingArgs = args.drop(paramsContainer.typeParameters.size) - val parentClass = paramsContainer.parents.firstIsInstanceOrNull() + val parentTypeContainer = paramsContainer.parents.firstIsInstanceOrNull() val parentUnspecialised = when { remainingArgs.isEmpty() -> true - parentClass == null -> false - else -> isUnspecialised(parentClass, remainingArgs) + parentTypeContainer == null -> { + logger.error("Found more type arguments than parameters: ${origParamsContainer.kotlinFqName.asString()}") + false + } + else -> isUnspecialised(parentTypeContainer, remainingArgs, logger, origParamsContainer) } return unspecialisedHere && parentUnspecialised } // Returns true if type is C where C is declared `class C { ... }` -fun isUnspecialised(type: IrSimpleType) = (type.classifier.owner as? IrClass)?.let { - isUnspecialised(it, type.arguments) +fun isUnspecialised(type: IrSimpleType, logger: Logger) = (type.classifier.owner as? IrClass)?.let { + isUnspecialised(it, type.arguments, logger) } ?: false diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/build.gradle b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/build.gradle new file mode 100644 index 00000000000..c0bc3340524 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/build.gradle @@ -0,0 +1,25 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Kotlin application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/7.0.2/userguide/building_java_projects.html + */ + +plugins { + // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. + id 'org.jetbrains.kotlin.jvm' version '1.7.0' + + // Apply the application plugin to add support for building a CLI application in Java. + id 'application' +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +application { + // Define the main class for the application. + mainClass = 'testProject.AppKt' +} diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/src/main/kotlin/testProject/App.kt b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/src/main/kotlin/testProject/App.kt new file mode 100644 index 00000000000..0ed9df24a57 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/app/src/main/kotlin/testProject/App.kt @@ -0,0 +1,15 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package testProject + +class App { + val greeting: String + get() { + return "Hello World!" + } +} + +fun main() { + // TODO: println(App().greeting) +} diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.expected b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.expected new file mode 100644 index 00000000000..d560b9b520d --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.expected @@ -0,0 +1,15 @@ +| 0 | -Xallow-no-source-files | +| 1 | -classpath | +| 2 | | +| 3 | -d | +| 4 | app/build/classes/kotlin/main | +| 5 | -jdk-home | +| 6 | | +| 7 | -module-name | +| 8 | app | +| 9 | -no-reflect | +| 10 | -no-stdlib | +| 11 | | +| 12 | app/src/main/kotlin/testProject/App.kt | +| 13 | -jvm-target | +| 14 | 1.8 | diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.ql b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.ql new file mode 100644 index 00000000000..fe4bedba634 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/compArgs.ql @@ -0,0 +1,15 @@ +import java + +private string getArgument(Compilation c, int i) { + exists(string arg | arg = c.getArgument(i) | + if exists(arg.indexOf("-Xplugin=")) + then result = "" + else + if c.getArgument(i - 1) = ["-classpath", "-jdk-home"] + then result = "" + else result = arg + ) +} + +from Compilation c, int i +select i, getArgument(c, i) diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/settings.gradle b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/settings.gradle new file mode 100644 index 00000000000..a56fb7dd11c --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/settings.gradle @@ -0,0 +1,11 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/7.0.2/userguide/multi_project_builds.html + */ + +rootProject.name = 'testProject' +include('app') diff --git a/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/test.py b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/test.py new file mode 100644 index 00000000000..e5e9aca69bc --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/compiler_arguments/test.py @@ -0,0 +1,5 @@ +from create_database_utils import * + +run_codeql_database_create( + ["gradle build --no-daemon --no-build-cache"], lang="java") +runSuccessfully(["gradle", "clean"]) diff --git a/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/build.gradle b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/build.gradle new file mode 100644 index 00000000000..924524190cf --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/build.gradle @@ -0,0 +1,25 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Kotlin application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/7.0.2/userguide/building_java_projects.html + */ + +plugins { + // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. + id 'org.jetbrains.kotlin.jvm' version '1.6.20' + + // Apply the application plugin to add support for building a CLI application in Java. + id 'application' +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +application { + // Define the main class for the application. + mainClass = 'testProject.AppKt' +} diff --git a/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/src/main/kotlin/testProject/App.kt b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/src/main/kotlin/testProject/App.kt new file mode 100644 index 00000000000..283f9270626 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/app/src/main/kotlin/testProject/App.kt @@ -0,0 +1,10 @@ +import kotlin.reflect.* + +fun fn() { + val ref: KFunction2 = Ccc::m + ref.invoke(Ccc(), 1) +} + +class Ccc { + fun m(i:Int):Double = 5.0 +} diff --git a/java/ql/test/query-tests/security/CWE-312/CleartextStorageAndroidDatabaseTest.expected b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/diagnostics.expected similarity index 100% rename from java/ql/test/query-tests/security/CWE-312/CleartextStorageAndroidDatabaseTest.expected rename to java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/diagnostics.expected diff --git a/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/diagnostics.ql b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/diagnostics.ql new file mode 100644 index 00000000000..071cbb1b6ec --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/diagnostics.ql @@ -0,0 +1,4 @@ +import java +import semmle.code.java.Diagnostics + +query predicate diag(Diagnostic d) { any() } diff --git a/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/settings.gradle b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/settings.gradle new file mode 100644 index 00000000000..a56fb7dd11c --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/settings.gradle @@ -0,0 +1,11 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/7.0.2/userguide/multi_project_builds.html + */ + +rootProject.name = 'testProject' +include('app') diff --git a/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/test.py b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/test.py new file mode 100644 index 00000000000..3a4f9d2032e --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/kotlin_kfunction/test.py @@ -0,0 +1,5 @@ +from create_database_utils import * + +run_codeql_database_create( + ["gradle build --no-daemon --no-build-cache --rerun-tasks"], lang="java") +runSuccessfully(["gradle", "clean"]) diff --git a/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md b/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md new file mode 100644 index 00000000000..8c8046670a1 --- /dev/null +++ b/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md @@ -0,0 +1,7 @@ +--- +category: deprecated +--- +* The predicate `Annotation.getAValue()` has been deprecated because it might lead to obtaining the value of the wrong annotation element by accident. `getValue(string)` (or one of the value type specific predicates) should be used to explicitly specify the name of the annotation element. +* The predicate `Annotation.getAValue(string)` has been renamed to `getAnArrayValue(string)`. +* The predicate `SuppressWarningsAnnotation.getASuppressedWarningLiteral()` has been deprecated because it unnecessarily restricts the result type; `getASuppressedWarning()` should be used instead. +* The predicates `TargetAnnotation.getATargetExpression()` and `RetentionAnnotation.getRetentionPolicyExpression()` have been deprecated because getting the enum constant read expression is rarely useful, instead the corresponding predicates for getting the name of the referenced enum constants should be used. diff --git a/java/ql/lib/change-notes/2022-04-01-annotation-features.md b/java/ql/lib/change-notes/2022-04-01-annotation-features.md new file mode 100644 index 00000000000..3a2d6e2561c --- /dev/null +++ b/java/ql/lib/change-notes/2022-04-01-annotation-features.md @@ -0,0 +1,9 @@ +--- +category: feature +--- +* The predicates of the CodeQL class `Annotation` have been improved: + * Convenience value type specific predicates have been added, such as `getEnumConstantValue(string)` or `getStringValue(string)`. + * Convenience predicates for elements with array values have been added, such as `getAnEnumConstantArrayValue(string)`. While the behavior of the existing predicates has not changed, usage of them should be reviewed (or replaced with the newly added predicate) to make sure they work correctly for elements with array values. + * Some internal CodeQL usage of the `Annotation` predicates has been adjusted and corrected; this might affect the results of some queries. +* New predicates have been added to the CodeQL class `Annotatable` to support getting declared and associated annotations. As part of that, `hasAnnotation()` has been changed to also consider inherited annotations, to be consistent with `hasAnnotation(string, string)` and `getAnAnnotation()`. The newly added predicate `hasDeclaredAnnotation()` can be used as replacement for the old functionality. +* New predicates have been added to the CodeQL class `AnnotationType` to simplify getting information about usage of JDK meta-annotations, such as `@Retention`. diff --git a/java/ql/lib/change-notes/2022-08-18-android-manifest-backup-predicate.md b/java/ql/lib/change-notes/2022-08-18-android-manifest-backup-predicate.md new file mode 100644 index 00000000000..0af4f964170 --- /dev/null +++ b/java/ql/lib/change-notes/2022-08-18-android-manifest-backup-predicate.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added a new predicate, `allowsBackup`, in the `AndroidApplicationXmlElement` class. This predicate detects if the application element does not disable the `android:allowBackup` attribute. diff --git a/java/ql/lib/change-notes/2022-08-19-string-taint-models.md b/java/ql/lib/change-notes/2022-08-19-string-taint-models.md new file mode 100644 index 00000000000..7d7404755ea --- /dev/null +++ b/java/ql/lib/change-notes/2022-08-19-string-taint-models.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added taint flow models for the `java.lang.String.(charAt|getBytes)` methods. +* Improved taint flow models for the `java.lang.String.(replace|replaceFirst|replaceAll)` methods. Additional results may be found where users do not properly sanitize their inputs. diff --git a/java/ql/lib/change-notes/2022-08-23-contentresolver-summaries.md b/java/ql/lib/change-notes/2022-08-23-contentresolver-summaries.md new file mode 100644 index 00000000000..03790ce61c6 --- /dev/null +++ b/java/ql/lib/change-notes/2022-08-23-contentresolver-summaries.md @@ -0,0 +1,10 @@ +--- +category: minorAnalysis +--- +* Added new flow steps for the following Android classes: + * `android.content.ContentResolver` + * `android.content.ContentProviderClient` + * `android.content.ContentProviderOperation` + * `android.content.ContentProviderOperation$Builder` + * `android.content.ContentProviderResult` + * `android.database.Cursor` diff --git a/java/ql/lib/change-notes/2022-08-25-taint-model-spring-crudrepository.md b/java/ql/lib/change-notes/2022-08-25-taint-model-spring-crudrepository.md new file mode 100644 index 00000000000..2d5fce9346f --- /dev/null +++ b/java/ql/lib/change-notes/2022-08-25-taint-model-spring-crudrepository.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow summary for `org.springframework.data.repository.CrudRepository.save()`. diff --git a/java/ql/lib/change-notes/2022-08-31-kotlin-stdlib.md b/java/ql/lib/change-notes/2022-08-31-kotlin-stdlib.md new file mode 100644 index 00000000000..c1288fd6568 --- /dev/null +++ b/java/ql/lib/change-notes/2022-08-31-kotlin-stdlib.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow sinks, sources and summaries for the Kotlin standard library. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-09-06-notificationcompat-summaries.md b/java/ql/lib/change-notes/2022-09-06-notificationcompat-summaries.md new file mode 100644 index 00000000000..e95ad457844 --- /dev/null +++ b/java/ql/lib/change-notes/2022-09-06-notificationcompat-summaries.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added new flow steps for `androidx.core.app.NotificationCompat` and its inner classes. + \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-09-07-implicit-pendingintents-compat-sinks.md b/java/ql/lib/change-notes/2022-09-07-implicit-pendingintents-compat-sinks.md new file mode 100644 index 00000000000..a1ae10ac7d5 --- /dev/null +++ b/java/ql/lib/change-notes/2022-09-07-implicit-pendingintents-compat-sinks.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added new sinks to the query `java/android/implict-pendingintents` to take into account the classes `androidx.core.app.NotificationManagerCompat` and `androidx.core.app.AlarmManagerCompat`. + \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md b/java/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md new file mode 100644 index 00000000000..efdaf85f2ed --- /dev/null +++ b/java/ql/lib/change-notes/2022-09-08-implicit-read-flowstates.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-09-13-Member-getQualifiedName.md b/java/ql/lib/change-notes/2022-09-13-Member-getQualifiedName.md new file mode 100644 index 00000000000..70b897911a8 --- /dev/null +++ b/java/ql/lib/change-notes/2022-09-13-Member-getQualifiedName.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* The `Member.getQualifiedName()` predicate result now includes the qualified name of the declaring type. diff --git a/java/ql/lib/change-notes/2022-09-16-dispatch-confidence.md b/java/ql/lib/change-notes/2022-09-16-dispatch-confidence.md new file mode 100644 index 00000000000..9287e9abae3 --- /dev/null +++ b/java/ql/lib/change-notes/2022-09-16-dispatch-confidence.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* The virtual dispatch relation used in data flow now favors summary models over source code for dispatch to interface methods from `java.util` unless there is evidence that a specific source implementation is reachable. This should provide increased precision for any projects that include, for example, custom `List` or `Map` implementations. diff --git a/java/ql/lib/change-notes/released/0.3.4.md b/java/ql/lib/change-notes/released/0.3.4.md index 3fcd4f17053..4270abf9774 100644 --- a/java/ql/lib/change-notes/released/0.3.4.md +++ b/java/ql/lib/change-notes/released/0.3.4.md @@ -19,7 +19,7 @@ ### Minor Analysis Improvements -* Added new flow steps for the classes `java.io.Path` and `java.nio.Paths`. +* Added new flow steps for the classes `java.nio.file.Path` and `java.nio.file.Paths`. * The class `AndroidFragment` now also models the Android Jetpack version of the `Fragment` class (`androidx.fragment.app.Fragment`). * Java 19 builds can now be extracted. There are no non-preview new language features in this release, so the only user-visible change is that the CodeQL extractor will now correctly trace compilations using the JDK 19 release of `javac`. * Classes and methods that are seen with several different paths during the extraction process (for example, packaged into different JAR files) now report an arbitrarily selected location via their `getLocation` and `hasLocationInfo` predicates, rather than reporting all of them. This may lead to reduced alert duplication. diff --git a/java/ql/lib/semmle/code/Location.qll b/java/ql/lib/semmle/code/Location.qll index c906b9f2407..256b831a8ad 100644 --- a/java/ql/lib/semmle/code/Location.qll +++ b/java/ql/lib/semmle/code/Location.qll @@ -216,7 +216,7 @@ private predicate fixedHasLocation(Top l, Location loc, File f) { min(Location candidateLoc | hasLocation(l, candidateLoc) | - candidateLoc order by candidateLoc.getFile().toString() + candidateLoc order by candidateLoc.getFile().getAbsolutePath() ) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _) diff --git a/java/ql/lib/semmle/code/java/Annotation.qll b/java/ql/lib/semmle/code/java/Annotation.qll index 0b83d3b435e..28f994053a2 100644 --- a/java/ql/lib/semmle/code/java/Annotation.qll +++ b/java/ql/lib/semmle/code/java/Annotation.qll @@ -44,12 +44,100 @@ class Annotation extends @annotation, Expr { result = this.getType().getAnnotationElement(name) } - /** Gets a value of an annotation element. */ - Expr getAValue() { filteredAnnotValue(this, _, result) } + /** + * DEPRECATED: Getting the value of _any_ annotation element is error-prone because + * it could lead to selecting the value of the wrong element by accident (for example + * when an annotation type is extended in the future). Prefer the predicate `getValue(string)` + * and explicitly specify the element name. Use `getValue(_)` if it is really desired to + * get the value of any element. + * + * Gets a value of an annotation element. This includes default values in case + * no explicit value is specified. For elements with an array value type this + * might have an `ArrayInit` as result. To properly handle array values, prefer + * the predicate `getAnArrayValue`. + */ + deprecated Expr getAValue() { filteredAnnotValue(this, _, result) } - /** Gets the value of the annotation element with the specified `name`. */ + /** + * Gets the value of the annotation element with the specified `name`. + * This includes default values in case no explicit value is specified. + * For elements with an array value type this might get an `ArrayInit` instance. + * To properly handle array values, prefer the predicate `getAnArrayValue`. + */ Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) } + /** + * Gets the value of the annotation element, if its type is not an array. + * This guarantees that for consistency even elements of type array with a + * single value have no result, to prevent accidental error-prone usage. + */ + private Expr getNonArrayValue(string name) { + result = this.getValue(name) and + not this.getAnnotationElement(name).getType() instanceof Array + } + + /** + * If the value type of the annotation element with the specified `name` is an enum type, + * gets the enum constant used as value for that element. This includes default values in + * case no explicit value is specified. + * + * If the element value type is an enum type array, use `getAnEnumConstantArrayValue`. + */ + EnumConstant getEnumConstantValue(string name) { + result = this.getNonArrayValue(name).(FieldRead).getField() + } + + /** + * If the value type of the annotation element with the specified `name` is `String`, + * gets the string value used for that element. This includes default values in case no + * explicit value is specified. + * + * If the element value type is a string array, use `getAStringArrayValue`. + */ + string getStringValue(string name) { + // Uses CompileTimeConstantExpr instead of StringLiteral because this can for example + // be a read from a final variable as well. + result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getStringValue() + } + + /** + * If the value type of the annotation element with the specified `name` is `int` or + * a smaller integral type or `char`, gets the int value used for that element. + * This includes default values in case no explicit value is specified. + * + * If the element value type is an `int` array or an array of a smaller integral + * type or `char`, use `getAnIntArrayValue`. + */ + int getIntValue(string name) { + // Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example + // be a read from a final variable as well. + result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getIntValue() and + // Verify that type is integral; ignore floating point elements with IntegerLiteral as value + this.getAnnotationElement(name).getType().hasName(["byte", "short", "int", "char"]) + } + + /** + * If the value type of the annotation element with the specified `name` is `boolean`, + * gets the boolean value used for that element. This includes default values in case + * no explicit value is specified. + */ + boolean getBooleanValue(string name) { + // Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example + // be a read from a final variable as well. + result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getBooleanValue() + } + + /** + * If the value type of the annotation element with the specified `name` is `java.lang.Class`, + * gets the type referred to by that `Class`. This includes default values in case no explicit + * value is specified. + * + * If the element value type is a `Class` array, use `getATypeArrayValue`. + */ + Type getTypeValue(string name) { + result = this.getNonArrayValue(name).(TypeLiteral).getReferencedType() + } + /** Gets the element being annotated. */ Element getTarget() { result = this.getAnnotatedElement() } @@ -60,16 +148,83 @@ class Annotation extends @annotation, Expr { /** * Gets a value of the annotation element with the specified `name`, which must be declared as an array - * type. + * type. This includes default values in case no explicit value is specified. * - * If the annotation element is defined with an array initializer, then the returned value will - * be one of the elements of that array. Otherwise, the returned value will be the single - * expression defined for the value. + * If the annotation element is defined with an array initializer, then the result will be one of the + * elements of that array. Otherwise, the result will be the single expression used as value. */ - Expr getAValue(string name) { + Expr getAnArrayValue(string name) { result = this.getArrayValue(name, _) } + + /** + * DEPRECATED: Predicate has been renamed to `getAnArrayValue` + */ + deprecated Expr getAValue(string name) { result = this.getAnArrayValue(name) } + + /** + * Gets a value of the annotation element with the specified `name`, which must be declared as an enum + * type array. This includes default values in case no explicit value is specified. + * + * If the annotation element is defined with an array initializer, then the result will be one of the + * elements of that array. Otherwise, the result will be the single expression used as value. + */ + EnumConstant getAnEnumConstantArrayValue(string name) { + result = this.getAnArrayValue(name).(FieldRead).getField() + } + + /** + * Gets a value of the annotation element with the specified `name`, which must be declared as a string + * array. This includes default values in case no explicit value is specified. + * + * If the annotation element is defined with an array initializer, then the result will be one of the + * elements of that array. Otherwise, the result will be the single expression used as value. + */ + string getAStringArrayValue(string name) { + result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getStringValue() + } + + /** + * Gets a value of the annotation element with the specified `name`, which must be declared as an `int` + * array or an array of a smaller integral type or `char`. This includes default values in case no + * explicit value is specified. + * + * If the annotation element is defined with an array initializer, then the result will be one of the + * elements of that array. Otherwise, the result will be the single expression used as value. + */ + int getAnIntArrayValue(string name) { + result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getIntValue() and + // Verify that type is integral; ignore floating point elements with IntegerLiteral as value + this.getAnnotationElement(name).getType().hasName(["byte[]", "short[]", "int[]", "char[]"]) + } + + /** + * Gets a value of the annotation element with the specified `name`, which must be declared as a `Class` + * array. This includes default values in case no explicit value is specified. + * + * If the annotation element is defined with an array initializer, then the result will be one of the + * elements of that array. Otherwise, the result will be the single expression used as value. + */ + Type getATypeArrayValue(string name) { + result = this.getAnArrayValue(name).(TypeLiteral).getReferencedType() + } + + /** + * Gets the value at a given index of the annotation element with the specified `name`, which must be + * declared as an array type. This includes default values in case no explicit value is specified. + * + * If the annotation element is defined with an array initializer, then the result will be the element + * at the given index of that array, starting at 0. Otherwise, the result will be the single expression + * defined for the value and the `index` will be 0. + */ + Expr getArrayValue(string name, int index) { this.getType().getAnnotationElement(name).getType() instanceof Array and exists(Expr value | value = this.getValue(name) | - if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value + if value instanceof ArrayInit + then + // TODO: Currently reports incorrect index values in some cases, see https://github.com/github/codeql/issues/8645 + result = value.(ArrayInit).getInit(index) + else ( + index = 0 and result = value + ) ) } @@ -99,19 +254,86 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) { /** An abstract representation of language elements that can be annotated. */ class Annotatable extends Element { - /** Holds if this element has an annotation. */ - predicate hasAnnotation() { exists(Annotation a | a.getAnnotatedElement() = this) } + /** + * Holds if this element has an annotation, including inherited annotations. + * The retention policy of the annotation type is not considered. + */ + predicate hasAnnotation() { exists(this.getAnAnnotation()) } - /** Holds if this element has the specified annotation. */ + /** + * Holds if this element has a declared annotation, excluding inherited annotations. + * The retention policy of the annotation type is not considered. + */ + predicate hasDeclaredAnnotation() { exists(this.getADeclaredAnnotation()) } + + /** + * Holds if this element has the specified annotation, including inherited + * annotations. The retention policy of the annotation type is not considered. + */ predicate hasAnnotation(string package, string name) { exists(AnnotationType at | at = this.getAnAnnotation().getType() | at.nestedName() = name and at.getPackage().getName() = package ) } - /** Gets an annotation that applies to this element. */ + /** + * Gets an annotation that applies to this element, including inherited annotations. + * The results only include _direct_ annotations; _indirect_ annotations, that is + * repeated annotations in an (implicit) container annotation, are not included. + * The retention policy of the annotation type is not considered. + */ cached - Annotation getAnAnnotation() { result.getAnnotatedElement() = this } + Annotation getAnAnnotation() { + // This predicate is overridden by Class to consider inherited annotations + result = this.getADeclaredAnnotation() + } + + /** + * Gets an annotation that is declared on this element, excluding inherited annotations. + * The retention policy of the annotation type is not considered. + */ + Annotation getADeclaredAnnotation() { result.getAnnotatedElement() = this } + + /** Gets an _indirect_ (= repeated) annotation. */ + private Annotation getAnIndirectAnnotation() { + // 'indirect' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html + exists(AnnotationType t, Annotation containerAnn | + t = result.getType() and + containerAnn = this.getADeclaredAnnotation() and + containerAnn.getType() = t.getContainingAnnotationType() + | + result = containerAnn.getAnArrayValue("value") + ) + } + + private Annotation getADeclaredAssociatedAnnotation(AnnotationType t) { + // Direct or indirect annotation + result.getType() = t and + result = [this.getADeclaredAnnotation(), this.getAnIndirectAnnotation()] + } + + private Annotation getAnAssociatedAnnotation(AnnotationType t) { + // 'associated' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html + if exists(this.getADeclaredAssociatedAnnotation(t)) + then result = this.getADeclaredAssociatedAnnotation(t) + else ( + // Only if neither a direct nor an indirect annotation is present look for an inherited one + t.isInherited() and + // @Inherited only works for classes; cast to Annotatable is necessary because predicate is private + result = this.(Class).getASupertype().(Class).(Annotatable).getAnAssociatedAnnotation(t) + ) + } + + /** + * Gets an annotation _associated_ with this element, that is: + * - An annotation directly present on this element, or + * - An annotation indirectly present on this element (in the form of a repeated annotation), or + * - If an annotation of a type is neither directly nor indirectly present + * the result is an associated inherited annotation (recursively) + * + * The retention policy of the annotation type is not considered. + */ + Annotation getAnAssociatedAnnotation() { result = this.getAnAssociatedAnnotation(_) } /** * Holds if this or any enclosing `Annotatable` has a `@SuppressWarnings("")` @@ -128,6 +350,11 @@ class Annotatable extends Element { or this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category) or + this.(LocalClassOrInterface) + .getLocalTypeDeclStmt() + .getEnclosingCallable() + .suppressesWarningsAbout(category) + or this.(LocalVariableDecl).getCallable().suppressesWarningsAbout(category) } } @@ -146,10 +373,79 @@ class AnnotationType extends Interface { /** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */ predicate isInherited() { - exists(Annotation ann | - ann.getAnnotatedElement() = this and - ann.getType().hasQualifiedName("java.lang.annotation", "Inherited") - ) + this.getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Inherited") + } + + /** Holds if this annotation type is annotated with the meta-annotation `@Documented`. */ + predicate isDocumented() { + this.getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Documented") + } + + /** + * Gets the retention policy of this annotation type, that is, the name of one of the + * enum constants of `java.lang.annotation.RetentionPolicy`. If this annotation type + * has no `@Retention` annotation, the result is `CLASS`. + */ + string getRetentionPolicy() { + if this.getADeclaredAnnotation() instanceof RetentionAnnotation + then result = this.getADeclaredAnnotation().(RetentionAnnotation).getRetentionPolicy() + else + // If not explicitly specified retention is CLASS + result = "CLASS" + } + + /** + * Holds if the element type is a possible target for this annotation type. + * The `elementType` is the name of one of the `java.lang.annotation.ElementType` + * enum constants. + * + * If this annotation type has no `@Target` annotation, it is considered to be applicable + * in all declaration contexts. This matches the behavior of the latest Java versions + * but differs from the behavior of older Java versions. This predicate must only be + * called with names of `ElementType` enum constants; for other values it might hold + * erroneously. + */ + bindingset[elementType] + predicate isATargetType(string elementType) { + /* + * Note: Cannot use a predicate with string as result because annotation type without + * explicit @Target can be applied in all declaration contexts, requiring to hardcode + * element types here; then the results could become outdated if this predicate is not + * updated for future JDK versions, or it could have irritating results, e.g. RECORD_COMPONENT + * for a database created for Java 8. + * + * Could in theory read java.lang.annotation.ElementType constants from database, but might + * be brittle in case ElementType is not present in the database for whatever reason. + */ + + if this.getADeclaredAnnotation() instanceof TargetAnnotation + then elementType = this.getADeclaredAnnotation().(TargetAnnotation).getATargetElementType() + else + /* + * Behavior for missing @Target annotation changed between Java versions. In older Java + * versions it allowed usage in most (but not all) declaration contexts. Then for Java 14 + * JDK-8231435 changed it to allow usage in all declaration and type contexts. In Java 17 + * it was changed by JDK-8261610 to only allow usage in all declaration contexts, but not + * in type contexts anymore. However, during these changes javac did not always comply with + * the specification, see for example JDK-8254023. + * + * For simplicity pretend the latest behavior defined by the JLS applied in all versions; + * that means any declaration context is allowed, but type contexts (represented by TYPE_USE, + * see JLS 17 section 9.6.4.1) are not allowed. + */ + + elementType != "TYPE_USE" + } + + /** Holds if this annotation type is annotated with the meta-annotation `@Repeatable`. */ + predicate isRepeatable() { this.getADeclaredAnnotation() instanceof RepeatableAnnotation } + + /** + * If this annotation type is annotated with the meta-annotation `@Repeatable`, + * gets the annotation type which acts as _containing annotation type_. + */ + AnnotationType getContainingAnnotationType() { + result = this.getADeclaredAnnotation().(RepeatableAnnotation).getContainingType() } } diff --git a/java/ql/lib/semmle/code/java/Dependency.qll b/java/ql/lib/semmle/code/java/Dependency.qll index a2bd8a84fdc..17236c6d05e 100644 --- a/java/ql/lib/semmle/code/java/Dependency.qll +++ b/java/ql/lib/semmle/code/java/Dependency.qll @@ -71,7 +71,8 @@ predicate depends(RefType t, RefType dep) { a.getAnnotatedElement().(Member).getDeclaringType() = t | usesType(a.getType(), dep) or - usesType(a.getAValue().getType(), dep) + usesType(a.getValue(_).getType(), dep) or + usesType(a.getAnArrayValue(_).getType(), dep) ) or // the type accessed in an `instanceof` expression in `t`. diff --git a/java/ql/lib/semmle/code/java/DependencyCounts.qll b/java/ql/lib/semmle/code/java/DependencyCounts.qll index b775e5fcf06..1010be48055 100644 --- a/java/ql/lib/semmle/code/java/DependencyCounts.qll +++ b/java/ql/lib/semmle/code/java/DependencyCounts.qll @@ -90,7 +90,7 @@ predicate numDepends(RefType t, RefType dep, int value) { | elem = a and usesType(a.getType(), dep) or - elem = a.getAValue() and + elem = [a.getValue(_), a.getAnArrayValue(_)] and elem.getFile().getExtension() = "java" and usesType(elem.(Expr).getType(), dep) ) diff --git a/java/ql/lib/semmle/code/java/JDKAnnotations.qll b/java/ql/lib/semmle/code/java/JDKAnnotations.qll index 2dff70c4d8e..502aef09075 100644 --- a/java/ql/lib/semmle/code/java/JDKAnnotations.qll +++ b/java/ql/lib/semmle/code/java/JDKAnnotations.qll @@ -18,14 +18,16 @@ class OverrideAnnotation extends Annotation { class SuppressWarningsAnnotation extends Annotation { SuppressWarningsAnnotation() { this.getType().hasQualifiedName("java.lang", "SuppressWarnings") } - /** Gets the `StringLiteral` of a warning suppressed by this annotation. */ - StringLiteral getASuppressedWarningLiteral() { - result = this.getAValue() or - result = this.getAValue().(ArrayInit).getAnInit() - } + /** + * DEPRECATED: This predicate restricts the results to `StringLiteral`; prefer `getASuppressedWarning()` + * to get the name of a suppressed warning. + * + * Gets the `StringLiteral` of a warning suppressed by this annotation. + */ + deprecated StringLiteral getASuppressedWarningLiteral() { result = this.getAnArrayValue("value") } /** Gets the name of a warning suppressed by this annotation. */ - string getASuppressedWarning() { result = this.getASuppressedWarningLiteral().getValue() } + string getASuppressedWarning() { result = this.getAStringArrayValue("value") } } /** A `@Target` annotation. */ @@ -33,18 +35,15 @@ class TargetAnnotation extends Annotation { TargetAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Target") } /** + * DEPRECATED: Getting the field access expression is rarely useful. Use `getATargetElementType()` + * to get the name of the target element. + * * Gets a target expression within this annotation. * * For example, the field access `ElementType.FIELD` is a target expression in * `@Target({ElementType.FIELD, ElementType.METHOD})`. */ - Expr getATargetExpression() { - not result instanceof ArrayInit and - ( - result = this.getAValue() or - result = this.getAValue().(ArrayInit).getAnInit() - ) - } + deprecated Expr getATargetExpression() { result = this.getAnArrayValue("value") } /** * Gets the name of a target element type. @@ -52,14 +51,7 @@ class TargetAnnotation extends Annotation { * For example, `METHOD` is the name of a target element type in * `@Target({ElementType.FIELD, ElementType.METHOD})`. */ - string getATargetElementType() { - exists(EnumConstant ec | - ec = this.getATargetExpression().(VarAccess).getVariable() and - ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType") - | - result = ec.getName() - ) - } + string getATargetElementType() { result = this.getAnEnumConstantArrayValue("value").getName() } } /** A `@Retention` annotation. */ @@ -67,12 +59,15 @@ class RetentionAnnotation extends Annotation { RetentionAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Retention") } /** + * DEPRECATED: Getting the field access expression is rarely useful. Use `getRetentionPolicy()` + * to get the name of the retention policy. + * * Gets the retention policy expression within this annotation. * * For example, the field access `RetentionPolicy.RUNTIME` is the * retention policy expression in `@Retention(RetentionPolicy.RUNTIME)`. */ - Expr getRetentionPolicyExpression() { result = this.getValue("value") } + deprecated Expr getRetentionPolicyExpression() { result = this.getValue("value") } /** * Gets the name of the retention policy of this annotation. @@ -80,14 +75,18 @@ class RetentionAnnotation extends Annotation { * For example, `RUNTIME` is the name of the retention policy * in `@Retention(RetentionPolicy.RUNTIME)`. */ - string getRetentionPolicy() { - exists(EnumConstant ec | - ec = this.getRetentionPolicyExpression().(VarAccess).getVariable() and - ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "RetentionPolicy") - | - result = ec.getName() - ) - } + string getRetentionPolicy() { result = this.getEnumConstantValue("value").getName() } +} + +/** A `@Repeatable` annotation. */ +class RepeatableAnnotation extends Annotation { + RepeatableAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Repeatable") } + + /** + * Gets the annotation type which acts as _containing type_, grouping multiple + * repeatable annotations together. + */ + AnnotationType getContainingType() { result = this.getTypeValue("value") } } /** @@ -119,11 +118,7 @@ abstract class NonReflectiveAnnotation extends Annotation { } library class StandardNonReflectiveAnnotation extends NonReflectiveAnnotation { StandardNonReflectiveAnnotation() { - exists(AnnotationType anntp | anntp = this.getType() | - anntp.hasQualifiedName("java.lang", "Override") or - anntp.hasQualifiedName("java.lang", "Deprecated") or - anntp.hasQualifiedName("java.lang", "SuppressWarnings") or - anntp.hasQualifiedName("java.lang", "SafeVarargs") - ) + this.getType() + .hasQualifiedName("java.lang", ["Override", "Deprecated", "SuppressWarnings", "SafeVarargs"]) } } diff --git a/java/ql/lib/semmle/code/java/JMX.qll b/java/ql/lib/semmle/code/java/JMX.qll index 16c8736059f..66aa951ba28 100644 --- a/java/ql/lib/semmle/code/java/JMX.qll +++ b/java/ql/lib/semmle/code/java/JMX.qll @@ -27,7 +27,7 @@ class MXBean extends ManagedBean { class RegisteredManagedBeanImpl extends Class { RegisteredManagedBeanImpl() { this.getAnAncestor() instanceof ManagedBean and - exists(JMXRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this) + exists(JmxRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this) } /** @@ -39,32 +39,35 @@ class RegisteredManagedBeanImpl extends Class { /** * A call that registers an object with the `MBeanServer`, directly or indirectly. */ -class JMXRegistrationCall extends MethodAccess { - JMXRegistrationCall() { this.getCallee() instanceof JMXRegistrationMethod } +class JmxRegistrationCall extends MethodAccess { + JmxRegistrationCall() { this.getCallee() instanceof JmxRegistrationMethod } /** * Gets the argument that represents the object in the registration call. */ Expr getObjectArgument() { - result = this.getArgument(this.getCallee().(JMXRegistrationMethod).getObjectPosition()) + result = this.getArgument(this.getCallee().(JmxRegistrationMethod).getObjectPosition()) } } +/** DEPRECATED: Alias for JmxRegistrationCall */ +deprecated class JMXRegistrationCall = JmxRegistrationCall; + /** * A method used to register `MBean` and `MXBean` instances with the `MBeanServer`. * * This is either the `registerMBean` method on `MBeanServer`, or it is a wrapper around that * registration method. */ -class JMXRegistrationMethod extends Method { - JMXRegistrationMethod() { +class JmxRegistrationMethod extends Method { + JmxRegistrationMethod() { // A direct registration with the `MBeanServer`. this.getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and this.getName() = "registerMBean" or // The `MBeanServer` is often wrapped by an application specific management class, so identify - // methods that wrap a call to another `JMXRegistrationMethod`. - exists(JMXRegistrationCall c | + // methods that wrap a call to another `JmxRegistrationMethod`. + exists(JmxRegistrationCall c | // This must be a call to another JMX registration method, where the object argument is an access // of one of the parameters of this method. c.getObjectArgument().(VarAccess).getVariable() = this.getAParameter() @@ -81,25 +84,37 @@ class JMXRegistrationMethod extends Method { result = 0 or // Identify the position in this method where the object parameter should be passed. - exists(JMXRegistrationCall c | + exists(JmxRegistrationCall c | c.getObjectArgument().(VarAccess).getVariable() = this.getParameter(result) ) } } +/** DEPRECATED: Alias for JmxRegistrationMethod */ +deprecated class JMXRegistrationMethod = JmxRegistrationMethod; + /** The class `javax.management.remote.JMXConnectorFactory`. */ -class TypeJMXConnectorFactory extends Class { - TypeJMXConnectorFactory() { +class TypeJmxConnectorFactory extends Class { + TypeJmxConnectorFactory() { this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory") } } +/** DEPRECATED: Alias for TypeJmxConnectorFactory */ +deprecated class TypeJMXConnectorFactory = TypeJmxConnectorFactory; + /** The class `javax.management.remote.JMXServiceURL`. */ -class TypeJMXServiceURL extends Class { - TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") } +class TypeJmxServiceUrl extends Class { + TypeJmxServiceUrl() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") } } +/** DEPRECATED: Alias for TypeJmxServiceUrl */ +deprecated class TypeJMXServiceURL = TypeJmxServiceUrl; + /** The class `javax.management.remote.rmi.RMIConnector`. */ -class TypeRMIConnector extends Class { - TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") } +class TypeRmiConnector extends Class { + TypeRmiConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") } } + +/** DEPRECATED: Alias for TypeRmiConnector */ +deprecated class TypeRMIConnector = TypeRmiConnector; diff --git a/java/ql/lib/semmle/code/java/Member.qll b/java/ql/lib/semmle/code/java/Member.qll index ef3546b0af8..456e6e8b12a 100644 --- a/java/ql/lib/semmle/code/java/Member.qll +++ b/java/ql/lib/semmle/code/java/Member.qll @@ -20,8 +20,14 @@ class Member extends Element, Annotatable, Modifiable, @member { /** Gets the type in which this member is declared. */ RefType getDeclaringType() { declaresMember(result, this) } - /** Gets the qualified name of this member. */ - string getQualifiedName() { result = this.getDeclaringType().getName() + "." + this.getName() } + /** + * Gets the qualified name of this member. + * This is useful for debugging, but for normal use `hasQualifiedName` + * is recommended, as it is more efficient. + */ + string getQualifiedName() { + result = this.getDeclaringType().getQualifiedName() + "." + this.getName() + } /** * Holds if this member has the specified name and is declared in the diff --git a/java/ql/lib/semmle/code/java/Modifier.qll b/java/ql/lib/semmle/code/java/Modifier.qll index 8f947383d1e..3d03851fcf5 100644 --- a/java/ql/lib/semmle/code/java/Modifier.qll +++ b/java/ql/lib/semmle/code/java/Modifier.qll @@ -7,7 +7,13 @@ import Element /** A modifier such as `private`, `static` or `abstract`. */ class Modifier extends Element, @modifier { /** Gets the element to which this modifier applies. */ - Element getElement() { hasModifier(result, this) } + Element getElement() { + hasModifier(result, this) and + // Kotlin "internal" elements may also get "public" modifiers, so we want to filter those out + not exists(Modifier mod2 | + hasModifier(result, mod2) and modifiers(this, "public") and modifiers(mod2, "internal") + ) + } override string getAPrimaryQlClass() { result = "Modifier" } } @@ -20,7 +26,7 @@ abstract class Modifiable extends Element { * For most purposes, the more specialized predicates `isAbstract`, `isPublic`, etc. * should be used. * - * Both this method and those specialized predicates take implicit modifiers into account. + * Those specialized predicates also take implicit modifiers into account. * For instance, non-default instance methods in interfaces are implicitly * abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")` * does not. diff --git a/java/ql/lib/semmle/code/java/NumberFormatException.qll b/java/ql/lib/semmle/code/java/NumberFormatException.qll index f8aab0ba26f..e3b83811cf0 100644 --- a/java/ql/lib/semmle/code/java/NumberFormatException.qll +++ b/java/ql/lib/semmle/code/java/NumberFormatException.qll @@ -15,7 +15,7 @@ private class SpecialMethodAccess extends MethodAccess { this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass) } - predicate throwsNFE() { + predicate throwsNfe() { this.isParseMethod("Byte", "parseByte") or this.isParseMethod("Short", "parseShort") or this.isParseMethod("Integer", "parseInt") or @@ -33,6 +33,9 @@ private class SpecialMethodAccess extends MethodAccess { this.isValueOfMethod("Float") or this.isValueOfMethod("Double") } + + /** DEPRECATED: Alias for throwsNfe */ + deprecated predicate throwsNFE() { this.throwsNfe() } } /** A `ClassInstanceExpr` that constructs a number from its string representation. */ @@ -43,7 +46,7 @@ private class SpecialClassInstanceExpr extends ClassInstanceExpr { this.getNumArgument() = 1 } - predicate throwsNFE() { + predicate throwsNfe() { this.isStringConstructor("Byte") or this.isStringConstructor("Short") or this.isStringConstructor("Integer") or @@ -51,6 +54,9 @@ private class SpecialClassInstanceExpr extends ClassInstanceExpr { this.isStringConstructor("Float") or this.isStringConstructor("Double") } + + /** DEPRECATED: Alias for throwsNfe */ + deprecated predicate throwsNFE() { this.throwsNfe() } } /** The class `java.lang.NumberFormatException`. */ @@ -59,7 +65,7 @@ class NumberFormatException extends RefType { } /** Holds if `java.lang.NumberFormatException` is caught. */ -predicate catchesNFE(TryStmt t) { +predicate catchesNfe(TryStmt t) { exists(CatchClause cc, LocalVariableDeclExpr v | t.getACatchClause() = cc and cc.getVariable() = v and @@ -67,7 +73,13 @@ predicate catchesNFE(TryStmt t) { ) } +/** DEPRECATED: Alias for catchesNfe */ +deprecated predicate catchesNFE = catchesNfe/1; + /** Holds if `java.lang.NumberFormatException` can be thrown. */ -predicate throwsNFE(Expr e) { - e.(SpecialClassInstanceExpr).throwsNFE() or e.(SpecialMethodAccess).throwsNFE() +predicate throwsNfe(Expr e) { + e.(SpecialClassInstanceExpr).throwsNfe() or e.(SpecialMethodAccess).throwsNfe() } + +/** DEPRECATED: Alias for throwsNfe */ +deprecated predicate throwsNFE = throwsNfe/1; diff --git a/java/ql/lib/semmle/code/java/PrintAst.qll b/java/ql/lib/semmle/code/java/PrintAst.qll index 9d88550faa3..b2937d67940 100644 --- a/java/ql/lib/semmle/code/java/PrintAst.qll +++ b/java/ql/lib/semmle/code/java/PrintAst.qll @@ -120,7 +120,7 @@ private newtype TPrintAstNode = shouldPrint(lvde, _) and lvde.getParent() instanceof SingleLocalVarDeclParent } or TAnnotationsNode(Annotatable ann) { - shouldPrint(ann, _) and ann.hasAnnotation() and not partOfAnnotation(ann) + shouldPrint(ann, _) and ann.hasDeclaredAnnotation() and not partOfAnnotation(ann) } or TParametersNode(Callable c) { shouldPrint(c, _) and not c.hasNoParameters() } or TBaseTypesNode(ClassOrInterface ty) { shouldPrint(ty, _) } or diff --git a/java/ql/lib/semmle/code/java/UnitTests.qll b/java/ql/lib/semmle/code/java/UnitTests.qll index e56b9a6dc23..38f37fa4ff0 100644 --- a/java/ql/lib/semmle/code/java/UnitTests.qll +++ b/java/ql/lib/semmle/code/java/UnitTests.qll @@ -161,15 +161,13 @@ class TestNGTestMethod extends Method { exists(TestNGTestAnnotation testAnnotation | testAnnotation = this.getAnAnnotation() and // The data provider must have the same name as the referenced data provider - result.getDataProviderName() = - testAnnotation.getValue("dataProvider").(StringLiteral).getValue() + result.getDataProviderName() = testAnnotation.getStringValue("dataProvider") | // Either the data provider should be on the current class, or a supertype this.getDeclaringType().getAnAncestor() = result.getDeclaringType() or // Or the data provider class should be declared - result.getDeclaringType() = - testAnnotation.getValue("dataProviderClass").(TypeLiteral).getReferencedType() + result.getDeclaringType() = testAnnotation.getTypeValue("dataProviderClass") ) } } @@ -227,9 +225,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation { /** * Gets a listener defined in this annotation. */ - TestNGListenerImpl getAListener() { - result = this.getAValue("value").(TypeLiteral).getReferencedType() - } + TestNGListenerImpl getAListener() { result = this.getATypeArrayValue("value") } } /** diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index d3f0492089d..5dada4f8532 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -12,6 +12,7 @@ * `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance` * - Negative Summaries: * `namespace; type; name; signature; provenance` + * A negative summary is used to indicate that there is no flow via a callable. * * The interpretation of a row is similar to API-graphs with a left-to-right * reading. @@ -116,10 +117,12 @@ private module Frameworks { private import semmle.code.java.frameworks.Retrofit private import semmle.code.java.frameworks.Stream private import semmle.code.java.frameworks.Strings + private import semmle.code.java.frameworks.Thymeleaf private import semmle.code.java.frameworks.ratpack.Ratpack private import semmle.code.java.frameworks.ratpack.RatpackExec private import semmle.code.java.frameworks.spring.SpringCache private import semmle.code.java.frameworks.spring.SpringContext + private import semmle.code.java.frameworks.spring.SpringData private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.frameworks.spring.SpringUtil private import semmle.code.java.frameworks.spring.SpringUi @@ -139,6 +142,7 @@ private module Frameworks { private import semmle.code.java.security.LdapInjection private import semmle.code.java.security.MvelInjection private import semmle.code.java.security.OgnlInjection + private import semmle.code.java.security.TemplateInjection private import semmle.code.java.security.XPath private import semmle.code.java.security.XsltInjection private import semmle.code.java.frameworks.Jdbc @@ -151,7 +155,7 @@ private module Frameworks { private import semmle.code.java.frameworks.JMS private import semmle.code.java.frameworks.RabbitMQ private import semmle.code.java.regex.RegexFlowModels - private import semmle.code.java.frameworks.KotlinStdLib + private import semmle.code.java.frameworks.kotlin.StdLib } /** @@ -623,7 +627,7 @@ module CsvValidation { "open-url", "jndi-injection", "ldap", "sql", "jdbc-url", "logging", "mvel", "xpath", "groovy", "xss", "ognl-injection", "intent-start", "pending-intent-sent", "url-open-stream", "url-redirect", "create-file", "write-file", "set-hostname-verifier", - "header-splitting", "information-leak", "xslt", "jexl", "bean-validation" + "header-splitting", "information-leak", "xslt", "jexl", "bean-validation", "ssti" ] and not kind.matches("regex-use%") and not kind.matches("qltest%") and diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll index fcd4fe90b6d..a6189337751 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll @@ -88,7 +88,7 @@ private class ReverseDnsSource extends RemoteFlowSource { ReverseDnsSource() { // Try not to trigger on `localhost`. exists(MethodAccess m | m = this.asExpr() | - m.getMethod() instanceof ReverseDNSMethod and + m.getMethod() instanceof ReverseDnsMethod and not exists(MethodAccess l | (variableStep(l, m.getQualifier()) or l = m.getQualifier()) and l.getMethod().getName() = "getLocalHost" @@ -221,8 +221,8 @@ class TypeInetAddr extends RefType { } /** A reverse DNS method. */ -class ReverseDNSMethod extends Method { - ReverseDNSMethod() { +class ReverseDnsMethod extends Method { + ReverseDnsMethod() { this.getDeclaringType() instanceof TypeInetAddr and ( this.getName() = "getHostName" or @@ -231,6 +231,9 @@ class ReverseDNSMethod extends Method { } } +/** DEPRECATED: Alias for ReverseDnsMethod */ +deprecated class ReverseDNSMethod = ReverseDnsMethod; + /** Android `Intent` that may have come from a hostile application. */ class AndroidIntentInput extends DataFlow::Node { Type receiverType; diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index 1b9842b9383..c3fd63cbf26 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -53,6 +53,16 @@ private class TypeFlowNode extends TTypeFlowNode { } } +private int getNodeKind(TypeFlowNode n) { + result = 1 and n instanceof TField + or + result = 2 and n instanceof TSsa + or + result = 3 and n instanceof TExpr + or + result = 4 and n instanceof TMethod +} + /** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */ private RefType boxIfNeeded(Type t) { t.(PrimitiveType).getBoxedType() = result or @@ -146,46 +156,199 @@ private predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep0(n1, n2) and not isNull(n1) } -private predicate joinStepRank1(int r, TypeFlowNode n1, TypeFlowNode n2) { - n1 = - rank[r](TypeFlowNode n | - joinStep(n, n2) - | - n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn() +private predicate anyStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep(n1, n2) or step(n1, n2) } + +private import SccReduction + +/** + * SCC reduction. + * + * This ought to be as easy as `equivalenceRelation(sccEdge/2)(n, scc)`, but + * this HOP is not currently supported for newtypes. + * + * A straightforward implementation would be: + * ```ql + * predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) { + * scc = + * max(TypeFlowNode n2 | + * sccEdge+(n, n2) + * | + * n2 + * order by + * n2.getLocation().getStartLine(), n2.getLocation().getStartColumn(), getNodeKind(n2) + * ) + * } + * + * ``` + * but this is quadratic in the size of the SCCs. + * + * Instead we find local maxima by following SCC edges and determine the SCC + * representatives from those. + * (This is still worst-case quadratic in the size of the SCCs, but generally + * performs better.) + */ +private module SccReduction { + private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) { + anyStep(n1, n2) and anyStep+(n2, n1) + } + + private predicate sccEdgeWithMax(TypeFlowNode n1, TypeFlowNode n2, TypeFlowNode m) { + sccEdge(n1, n2) and + m = + max(TypeFlowNode n | + n = [n1, n2] + | + n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn(), getNodeKind(n) + ) + } + + private predicate hasLargerNeighbor(TypeFlowNode n) { + exists(TypeFlowNode n2 | + sccEdgeWithMax(n, n2, n2) and + not sccEdgeWithMax(n, n2, n) + or + sccEdgeWithMax(n2, n, n2) and + not sccEdgeWithMax(n2, n, n) ) + } + + private predicate localMax(TypeFlowNode m) { + sccEdgeWithMax(_, _, m) and + not hasLargerNeighbor(m) + } + + private predicate sccReprFromLocalMax(TypeFlowNode scc) { + exists(TypeFlowNode m | + localMax(m) and + scc = + max(TypeFlowNode n2 | + sccEdge+(m, n2) and localMax(n2) + | + n2 + order by + n2.getLocation().getStartLine(), n2.getLocation().getStartColumn(), getNodeKind(n2) + ) + ) + } + + /** Holds if `n` is part of an SCC of size 2 or more represented by `scc`. */ + predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) { + sccEdge+(n, scc) and sccReprFromLocalMax(scc) + } + + predicate sccJoinStep(TypeFlowNode n, TypeFlowNode scc) { + exists(TypeFlowNode mid | + joinStep(n, mid) and + sccRepr(mid, scc) and + not sccRepr(n, scc) + ) + } } -private predicate joinStepRank2(int r2, int r1, TypeFlowNode n) { - r1 = rank[r2](int r | joinStepRank1(r, _, n) | r) +private signature predicate edgeSig(TypeFlowNode n1, TypeFlowNode n2); + +private signature module RankedEdge { + predicate edgeRank(int r, TypeFlowNode n1, TypeFlowNode n2); + + int lastRank(TypeFlowNode n); } -private predicate joinStepRank(int r, TypeFlowNode n1, TypeFlowNode n2) { - exists(int r1 | - joinStepRank1(r1, n1, n2) and - joinStepRank2(r, r1, n2) - ) +private module RankEdge implements RankedEdge { + /** + * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used + * ordering is not necessarily total, so the ranking may have gaps. + */ + private predicate edgeRank1(int r, TypeFlowNode n1, TypeFlowNode n2) { + n1 = + rank[r](TypeFlowNode n | + edge(n, n2) + | + n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn() + ) + } + + /** + * Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the + * gaps from the ranking. + */ + private predicate edgeRank2(int r2, int r1, TypeFlowNode n) { + r1 = rank[r2](int r | edgeRank1(r, _, n) | r) + } + + /** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */ + predicate edgeRank(int r, TypeFlowNode n1, TypeFlowNode n2) { + exists(int r1 | + edgeRank1(r1, n1, n2) and + edgeRank2(r, r1, n2) + ) + } + + int lastRank(TypeFlowNode n) { result = max(int r | edgeRank(r, _, n)) } } -private int lastRank(TypeFlowNode n) { result = max(int r | joinStepRank(r, _, n)) } +private signature module TypePropagation { + class Typ; + + predicate candType(TypeFlowNode n, Typ t); + + bindingset[t] + predicate supportsType(TypeFlowNode n, Typ t); +} + +/** Implements recursion through `forall` by way of edge ranking. */ +private module ForAll { + /** + * Holds if `t` is a bound that holds on one of the incoming edges to `n` and + * thus is a candidate bound for `n`. + */ + pragma[nomagic] + private predicate candJoinType(TypeFlowNode n, T::Typ t) { + exists(TypeFlowNode mid | + T::candType(mid, t) and + Edge::edgeRank(_, mid, n) + ) + } + + /** + * Holds if `t` is a candidate bound for `n` that is also valid for data coming + * through the edges into `n` ranked from `1` to `r`. + */ + private predicate flowJoin(int r, TypeFlowNode n, T::Typ t) { + ( + r = 1 and candJoinType(n, t) + or + flowJoin(r - 1, n, t) and Edge::edgeRank(r, _, n) + ) and + forall(TypeFlowNode mid | Edge::edgeRank(r, mid, n) | T::supportsType(mid, t)) + } + + /** + * Holds if `t` is a candidate bound for `n` that is also valid for data + * coming through all the incoming edges, and therefore is a valid bound for + * `n`. + */ + predicate flowJoin(TypeFlowNode n, T::Typ t) { flowJoin(Edge::lastRank(n), n, t) } +} + +module RankedJoinStep = RankEdge; + +module RankedSccJoinStep = RankEdge; private predicate exactTypeBase(TypeFlowNode n, RefType t) { exists(ClassInstanceExpr e | n.asExpr() = e and e.getType() = t and not e instanceof FunctionalExpr and - exists(RefType sub | sub.getASourceSupertype() = t.getSourceDeclaration()) + exists(SrcRefType sub | sub.getASourceSupertype() = t.getSourceDeclaration()) ) } -private predicate exactTypeRank(int r, TypeFlowNode n, RefType t) { - forall(TypeFlowNode mid | joinStepRank(r, mid, n) | exactType(mid, t)) and - joinStepRank(r, _, n) -} +private module ExactTypePropagation implements TypePropagation { + class Typ = RefType; -private predicate exactTypeJoin(int r, TypeFlowNode n, RefType t) { - exactTypeRank(1, n, t) and r = 1 - or - exactTypeJoin(r - 1, n, t) and exactTypeRank(r, n, t) + predicate candType = exactType/2; + + predicate supportsType = exactType/2; } /** @@ -199,43 +362,60 @@ private predicate exactType(TypeFlowNode n, RefType t) { or // The following is an optimized version of // `forex(TypeFlowNode mid | joinStep(mid, n) | exactType(mid, t))` - exactTypeJoin(lastRank(n), n, t) + ForAll::flowJoin(n, t) + or + exists(TypeFlowNode scc | + sccRepr(n, scc) and + // Optimized version of + // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | exactType(mid, t))` + ForAll::flowJoin(scc, t) + ) } /** * Holds if `n` occurs in a position where type information might be discarded; - * `t` is the potentially boxed type of `n`, `t1` is the erasure of `t`, and - * `t2` is the erased type of the implicit or explicit cast. + * `t1` is the type of `n`, `t1e` is the erasure of `t1`, `t2` is the type of + * the implicit or explicit cast, and `t2e` is the erasure of `t2`. */ -pragma[noinline] -private predicate upcastCand(TypeFlowNode n, RefType t, RefType t1, RefType t2) { - t = boxIfNeeded(n.getType()) and - t.getErasure() = t1 and - ( - exists(Variable v | v.getAnAssignedValue() = n.asExpr() and t2 = v.getType().getErasure()) - or - exists(CastingExpr c | c.getExpr() = n.asExpr() and t2 = c.getType().getErasure()) - or - exists(ReturnStmt ret | - ret.getResult() = n.asExpr() and t2 = ret.getEnclosingCallable().getReturnType().getErasure() - ) - or - exists(MethodAccess ma | viableImpl_v1(ma) = n.asMethod() and t2 = ma.getType()) - or - exists(Parameter p | privateParamArg(p, n.asExpr()) and t2 = p.getType().getErasure()) - or - exists(ChooseExpr cond | - cond.getAResultExpr() = n.asExpr() and - t2 = cond.getType().getErasure() - ) +pragma[nomagic] +private predicate upcastCand(TypeFlowNode n, RefType t1, RefType t1e, RefType t2, RefType t2e) { + exists(TypeFlowNode next | step(n, next) or joinStep(n, next) | + n.getType() = t1 and + next.getType() = t2 and + t1.getErasure() = t1e and + t2.getErasure() = t2e and + t1 != t2 + ) +} + +private predicate unconstrained(BoundedType t) { + t.(Wildcard).isUnconstrained() + or + t.getUpperBoundType() instanceof TypeObject and + not t.(Wildcard).hasLowerBound() + or + unconstrained(t.getUpperBoundType()) + or + unconstrained(t.(Wildcard).getLowerBoundType()) +} + +/** Holds if `t` is a raw type or parameterised type with unrestricted type arguments. */ +private predicate unbound(RefType t) { + t instanceof RawType + or + exists(ParameterizedType pt | pt = t | + forex(RefType arg | arg = pt.getATypeArgument() | unconstrained(arg)) ) } /** Holds if `n` occurs in a position where type information is discarded. */ -private predicate upcast(TypeFlowNode n, RefType t) { - exists(RefType t1, RefType t2 | - upcastCand(n, t, t1, t2) and - t1.getASourceSupertype+() = t2 +private predicate upcast(TypeFlowNode n, RefType t1) { + exists(RefType t1e, RefType t2, RefType t2e | upcastCand(n, t1, t1e, t2, t2e) | + t1e.getASourceSupertype+() = t2e + or + t1e = t2e and + unbound(t2) and + not unbound(t1) ) } @@ -322,9 +502,10 @@ predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) { /** * Holds if `n` has type `t` and this information is discarded, such that `t` - * might be a better type bound for nodes where `n` flows to. + * might be a better type bound for nodes where `n` flows to. This might include + * multiple bounds for a single node. */ -private predicate typeFlowBase(TypeFlowNode n, RefType t) { +private predicate typeFlowBaseCand(TypeFlowNode n, RefType t) { exists(RefType srctype | upcast(n, srctype) or upcastEnhancedForStmt(n.asSsa(), srctype) or @@ -340,29 +521,36 @@ private predicate typeFlowBase(TypeFlowNode n, RefType t) { } /** - * Holds if `t` is a bound that holds on one of the incoming edges to `n` and - * thus is a candidate bound for `n`. + * Holds if `n` has type `t` and this information is discarded, such that `t` + * might be a better type bound for nodes where `n` flows to. This only includes + * the best such bound for each node. */ -pragma[noinline] -private predicate typeFlowJoinCand(TypeFlowNode n, RefType t) { - exists(TypeFlowNode mid | joinStep(mid, n) | typeFlow(mid, t)) +private predicate typeFlowBase(TypeFlowNode n, RefType t) { + exists(RefType te | + typeFlowBaseCand(n, t) and + te = t.getErasure() and + not exists(RefType better | + typeFlowBaseCand(n, better) and + better != t and + not t.getASupertype+() = better + | + better.getASupertype+() = t or + better.getErasure().(RefType).getASourceSupertype+() = te + ) + ) } -/** - * Holds if `t` is a candidate bound for `n` that is also valid for data coming - * through the edges into `n` ranked from `1` to `r`. - */ -private predicate typeFlowJoin(int r, TypeFlowNode n, RefType t) { - ( - r = 1 and typeFlowJoinCand(n, t) - or - typeFlowJoin(r - 1, n, t) and joinStepRank(r, _, n) - ) and - forall(TypeFlowNode mid | joinStepRank(r, mid, n) | +private module TypeFlowPropagation implements TypePropagation { + class Typ = RefType; + + predicate candType = typeFlow/2; + + bindingset[t] + predicate supportsType(TypeFlowNode mid, RefType t) { exists(RefType midtyp | exactType(mid, midtyp) or typeFlow(mid, midtyp) | pragma[only_bind_out](midtyp).getAnAncestor() = t ) - ) + } } /** @@ -374,7 +562,12 @@ private predicate typeFlow(TypeFlowNode n, RefType t) { or exists(TypeFlowNode mid | typeFlow(mid, t) and step(mid, n)) or - typeFlowJoin(lastRank(n), n, t) + ForAll::flowJoin(n, t) + or + exists(TypeFlowNode scc | + sccRepr(n, scc) and + ForAll::flowJoin(scc, t) + ) } pragma[nomagic] @@ -429,6 +622,175 @@ private predicate bestTypeFlow(TypeFlowNode n, RefType t) { not irrelevantBound(n, t) } +private predicate bestTypeFlow(TypeFlowNode n, RefType t, boolean exact) { + exactType(n, t) and exact = true + or + not exactType(n, _) and bestTypeFlow(n, t) and exact = false +} + +private predicate bestTypeFlowOrTypeFlowBase(TypeFlowNode n, RefType t, boolean exact) { + bestTypeFlow(n, t, exact) + or + typeFlowBase(n, t) and + exact = false and + not bestTypeFlow(n, _, _) +} + +/** + * Holds if `n` has type `t` and this information is not propagated as a + * universal bound to a subsequent node, such that `t` might form the basis for + * a union type bound for that node. + */ +private predicate unionTypeFlowBaseCand(TypeFlowNode n, RefType t, boolean exact) { + exists(TypeFlowNode next | + joinStep(n, next) and + bestTypeFlowOrTypeFlowBase(n, t, exact) and + not bestTypeFlowOrTypeFlowBase(next, t, exact) and + not exactType(next, _) + ) +} + +/** + * Holds if `ioe` checks `v`, its true-successor is `bb`, and `bb` has multiple + * predecessors. + */ +private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) { + ioe.getExpr() = v.getAUse() and + strictcount(bb.getABBPredecessor()) > 1 and + exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb) +} + +/** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */ +private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) { + strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) = + strictcount(bb.getABBPredecessor()) +} + +/** + * Holds if `n` is a value that is guarded by a disjunction of + * `instanceof t_i` where `t` is one of those `t_i`. + */ +private predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) { + exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va | + instanceofDisjunction(bb, v) and + bb.bbDominates(va.getBasicBlock()) and + va = v.getAUse() and + instanceofDisjunct(ioe, bb, v) and + t = ioe.getCheckedType() and + n.asExpr() = va + ) +} + +private module HasUnionTypePropagation implements TypePropagation { + class Typ = Unit; + + predicate candType(TypeFlowNode mid, Unit unit) { + exists(unit) and + (unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid)) + } + + predicate supportsType = candType/2; +} + +/** + * Holds if all incoming type flow can be traced back to a + * `unionTypeFlowBaseCand`, such that we can compute a union type bound for `n`. + * Disregards nodes for which we have an exact bound. + */ +private predicate hasUnionTypeFlow(TypeFlowNode n) { + not exactType(n, _) and + ( + // Optimized version of + // `forex(TypeFlowNode mid | joinStep(mid, n) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))` + ForAll::flowJoin(n, _) + or + exists(TypeFlowNode scc | + sccRepr(n, scc) and + // Optimized version of + // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))` + ForAll::flowJoin(scc, _) + ) + or + exists(TypeFlowNode mid | step(mid, n) and hasUnionTypeFlow(mid)) + or + instanceofDisjunctionGuarded(n, _) + ) +} + +pragma[nomagic] +private RefType getTypeBound(TypeFlowNode n) { + bestTypeFlow(n, result) + or + not bestTypeFlow(n, _) and result = n.getType() +} + +pragma[nomagic] +private predicate unionTypeFlow0(TypeFlowNode n, RefType t, boolean exact) { + hasUnionTypeFlow(n) and + ( + exists(TypeFlowNode mid | anyStep(mid, n) | + unionTypeFlowBaseCand(mid, t, exact) or unionTypeFlow(mid, t, exact) + ) + or + instanceofDisjunctionGuarded(n, t) and exact = false + ) +} + +/** Holds if we have a union type bound for `n` and `t` is one of its parts. */ +private predicate unionTypeFlow(TypeFlowNode n, RefType t, boolean exact) { + unionTypeFlow0(n, t, exact) and + // filter impossible union parts: + if exact = true + then t.getErasure().(RefType).getASourceSupertype*() = getTypeBound(n).getErasure() + else haveIntersection(getTypeBound(n), t) +} + +/** + * Holds if the inferred union type bound for `n` contains the best universal + * bound and thus is irrelevant. + */ +private predicate irrelevantUnionType(TypeFlowNode n) { + exists(RefType t, RefType nt, RefType te, RefType nte | + unionTypeFlow(n, t, false) and + nt = getTypeBound(n) and + te = t.getErasure() and + nte = nt.getErasure() + | + nt.getASupertype*() = t + or + nte.getASourceSupertype+() = te + or + nte = te and unbound(t) + ) +} + +/** + * Holds if `t` is an irrelevant part of the union type bound for `n` due to + * being contained in another part of the union type bound. + */ +private predicate irrelevantUnionTypePart(TypeFlowNode n, RefType t, boolean exact) { + unionTypeFlow(n, t, exact) and + not irrelevantUnionType(n) and + exists(RefType weaker | + unionTypeFlow(n, weaker, false) and + t.getASupertype*() = weaker + | + exact = true or not weaker.getASupertype*() = t + ) +} + +/** + * Holds if the runtime type of `n` is bounded by a union type and if this + * bound is likely to be better than the static type of `n`. The union type is + * made up of the types `t` related to `n` by this predicate, and the flag + * `exact` indicates whether `t` is an exact bound or merely an upper bound. + */ +private predicate bestUnionType(TypeFlowNode n, RefType t, boolean exact) { + unionTypeFlow(n, t, exact) and + not irrelevantUnionType(n) and + not irrelevantUnionTypePart(n, t, exact) +} + cached private module TypeFlowBounds { /** @@ -440,11 +802,7 @@ private module TypeFlowBounds { predicate fieldTypeFlow(Field f, RefType t, boolean exact) { exists(TypeFlowNode n | n.asField() = f and - ( - exactType(n, t) and exact = true - or - not exactType(n, _) and bestTypeFlow(n, t) and exact = false - ) + bestTypeFlow(n, t, exact) ) } @@ -457,11 +815,21 @@ private module TypeFlowBounds { predicate exprTypeFlow(Expr e, RefType t, boolean exact) { exists(TypeFlowNode n | n.asExpr() = e and - ( - exactType(n, t) and exact = true - or - not exactType(n, _) and bestTypeFlow(n, t) and exact = false - ) + bestTypeFlow(n, t, exact) + ) + } + + /** + * Holds if the runtime type of `e` is bounded by a union type and if this + * bound is likely to be better than the static type of `e`. The union type is + * made up of the types `t` related to `e` by this predicate, and the flag + * `exact` indicates whether `t` is an exact bound or merely an upper bound. + */ + cached + predicate exprUnionTypeFlow(Expr e, RefType t, boolean exact) { + exists(TypeFlowNode n | + n.asExpr() = e and + bestUnionType(n, t, exact) ) } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll index 543c392817c..a57d1ca32be 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -4,11 +4,31 @@ private import DataFlowUtil private import semmle.code.java.dataflow.InstanceAccess private import semmle.code.java.dataflow.FlowSummary private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch +private import semmle.code.java.dataflow.TypeFlow +private import semmle.code.java.dispatch.internal.Unification private module DispatchImpl { + private predicate hasHighConfidenceTarget(Call c) { + exists(SummarizedCallable sc | + sc = c.getCallee().getSourceDeclaration() and not sc.isAutoGenerated() + ) + or + exists(Callable srcTgt | + srcTgt = VirtualDispatch::viableCallable(c) and + not VirtualDispatch::lowConfidenceDispatchTarget(c, srcTgt) + ) + } + + private Callable sourceDispatch(Call c) { + result = VirtualDispatch::viableCallable(c) and + if VirtualDispatch::lowConfidenceDispatchTarget(c, result) + then not hasHighConfidenceTarget(c) + else any() + } + /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall c) { - result.asCallable() = VirtualDispatch::viableCallable(c.asCall()) + result.asCallable() = sourceDispatch(c.asCall()) or result.asSummarizedCallable() = c.asCall().getCallee().getSourceDeclaration() } @@ -20,7 +40,7 @@ private module DispatchImpl { */ private predicate mayBenefitFromCallContext(MethodAccess ma, Callable c, int i) { exists(Parameter p | - 2 <= strictcount(VirtualDispatch::viableImpl(ma)) and + 2 <= strictcount(sourceDispatch(ma)) and ma.getQualifier().(VarAccess).getVariable() = p and p.getPosition() = i and c.getAParameter() = p and @@ -29,7 +49,7 @@ private module DispatchImpl { ) or exists(OwnInstanceAccess ia | - 2 <= strictcount(VirtualDispatch::viableImpl(ma)) and + 2 <= strictcount(sourceDispatch(ma)) and (ia.isExplicit(ma.getQualifier()) or ia.isImplicitMethodQualifier(ma)) and i = -1 and c = ma.getEnclosingCallable() @@ -45,7 +65,7 @@ private module DispatchImpl { private predicate relevantContext(Call ctx, int i) { exists(Callable c | mayBenefitFromCallContext(_, c, i) and - c = VirtualDispatch::viableCallable(ctx) + c = sourceDispatch(ctx) ) } @@ -62,15 +82,21 @@ private module DispatchImpl { private predicate contextArgHasType(Call ctx, int i, RefType t, boolean exact) { relevantContext(ctx, i) and exists(RefType srctype | - exists(Expr arg, Expr src | + exists(Expr arg | i = -1 and ctx.getQualifier() = arg or ctx.getArgument(i) = arg | - src = VirtualDispatch::variableTrack(arg) and - srctype = getPreciseType(src) and - if src instanceof ClassInstanceExpr then exact = true else exact = false + exprTypeFlow(arg, srctype, exact) + or + not exprTypeFlow(arg, _, _) and + exprUnionTypeFlow(arg, srctype, exact) + or + not exprTypeFlow(arg, _, _) and + not exprUnionTypeFlow(arg, _, _) and + srctype = getPreciseType(arg) and + if arg instanceof ClassInstanceExpr then exact = true else exact = false ) or exists(Node arg | @@ -115,74 +141,20 @@ private module DispatchImpl { exact = false and exists(RefType t2 | result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and - not failsUnification(t, t2) + not Unification::failsUnification(t, t2) ) or result.asSummarizedCallable() = def ) } - pragma[noinline] - private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) { - contextArgHasType(_, _, t1, _) and t1.getGenericType() = g + private predicate unificationTargetLeft(ParameterizedType t1) { contextArgHasType(_, _, t1, _) } + + private predicate unificationTargetRight(ParameterizedType t2) { + exists(VirtualDispatch::viableMethodImpl(_, _, t2)) } - pragma[noinline] - private predicate unificationTargetRight(ParameterizedType t2, GenericType g) { - exists(VirtualDispatch::viableMethodImpl(_, _, t2)) and t2.getGenericType() = g - } - - private predicate unificationTargets(Type t1, Type t2) { - exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g)) - or - exists(Array a1, Array a2 | - unificationTargets(a1, a2) and - t1 = a1.getComponentType() and - t2 = a2.getComponentType() - ) - or - exists(ParameterizedType pt1, ParameterizedType pt2, int pos | - unificationTargets(pt1, pt2) and - not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and - t1 = pt1.getTypeArgument(pos) and - t2 = pt2.getTypeArgument(pos) - ) - } - - pragma[noinline] - private predicate typeArgsOfUnificationTargets( - ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2 - ) { - unificationTargets(t1, t2) and - arg1 = t1.getTypeArgument(pos) and - arg2 = t2.getTypeArgument(pos) - } - - private predicate failsUnification(Type t1, Type t2) { - unificationTargets(t1, t2) and - ( - exists(RefType arg1, RefType arg2 | - typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and - failsUnification(arg1, arg2) - ) - or - failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType()) - or - not ( - t1 instanceof Array and t2 instanceof Array - or - t1.(PrimitiveType) = t2.(PrimitiveType) - or - t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration() - or - t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration() - or - t1 instanceof BoundedType and t2 instanceof RefType - or - t1 instanceof RefType and t2 instanceof BoundedType - ) - ) - } + private module Unification = MkUnification; private int parameterPosition() { result in [-1, any(Parameter p).getPosition()] } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll index e00fc952e1c..d857cdaa359 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll @@ -226,15 +226,6 @@ module Public { none() } - /** - * Holds if values stored inside `content` are cleared on objects passed as - * arguments at position `pos` to this callable. - * - * TODO: Remove once all languages support `WithoutContent` tokens. - */ - pragma[nomagic] - predicate clearsContent(ParameterPosition pos, ContentSet content) { none() } - /** * Holds if the summary is auto generated. */ @@ -328,23 +319,6 @@ module Private { SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and preservesValue = preservesValue1.booleanAnd(preservesValue2) ) - or - exists(ParameterPosition ppos, ContentSet cs | - c.clearsContent(ppos, cs) and - input = SummaryComponentStack::push(SummaryComponent::withoutContent(cs), output) and - output = SummaryComponentStack::argument(ppos) and - preservesValue = true - ) - } - - private class MkClearStack extends RequiredSummaryComponentStack { - override predicate required(SummaryComponent head, SummaryComponentStack tail) { - exists(SummarizedCallable sc, ParameterPosition ppos, ContentSet cs | - sc.clearsContent(ppos, cs) and - head = SummaryComponent::withoutContent(cs) and - tail = SummaryComponentStack::argument(ppos) - ) - } } /** @@ -945,8 +919,7 @@ module Private { AccessPath inSpec, AccessPath outSpec, string kind ) { summaryElement(this, inSpec, outSpec, kind, true) and - not summaryElement(this, _, _, _, false) and - not this.clearsContent(_, _) + not summaryElement(this, _, _, _, false) } private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/NegativeSummary.qll b/java/ql/lib/semmle/code/java/dataflow/internal/NegativeSummary.qll new file mode 100644 index 00000000000..e7b6b7b8838 --- /dev/null +++ b/java/ql/lib/semmle/code/java/dataflow/internal/NegativeSummary.qll @@ -0,0 +1,9 @@ +/** Provides modules for importing negative summaries. */ + +/** + * 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.java.frameworks.GeneratedNegative +} diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index e00dee7c8dd..d52b340e67a 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -251,7 +251,7 @@ private predicate qualifierToArgumentStep(Expr tracked, Expr sink) { /** Access to a method that passes taint from the qualifier. */ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { - (taintPreservingQualifierToMethod(sink.getMethod()) or unsafeEscape(sink)) and + taintPreservingQualifierToMethod(sink.getMethod()) and tracked = sink.getQualifier() } @@ -282,28 +282,6 @@ private predicate taintPreservingQualifierToMethod(Method m) { ) } -private class StringReplaceMethod extends TaintPreservingCallable { - StringReplaceMethod() { - this.getDeclaringType() instanceof TypeString and - ( - this.hasName("replace") or - this.hasName("replaceAll") or - this.hasName("replaceFirst") - ) - } - - override predicate returnsTaintFrom(int arg) { arg = 1 } -} - -private predicate unsafeEscape(MethodAccess ma) { - // Removing `